Compare commits

...

19 Commits

Author SHA1 Message Date
Frog Business a57bd54811 Merge 02026c3d38 into 9c12f52805 2025-01-30 15:42:22 -08:00
Evan Husted 9c12f52805 UI: Pretty Atmosphère mod names (#601)
Changes the mods from the Atmosphère folder to show a pretty name
instead of just the name of the folder they're in, because those names
are always just a title ID.

NOTE: The DLC names are from the file names, not retrieved from the
content file itself like the main applications.
2025-01-30 17:41:25 -06:00
Otozinclus 059fc83d4d Add more games to Metal Auto list (#592)
ARMS: Tested every character and every Map, played a cup as well. It
works flawless in my testing. (If it freezes, that is caused by the
Hypervisor, not Metal. You need to disable the Hypervisor for this game)

Luigi's Mansion 2 HD: I tested every world a bit and had no issue. Isaac
said he specifically worked on it as well

Following games were flawless in my testing, but I only tested earlier
parts of the game so far, a late game part might have an issue,
therefore I will further test these in the future:

- Astral Chain
- Bayonetta Origins
- New Pokemon Snap
2025-01-30 17:22:00 -06:00
Evan Husted 04ce7fb764 misc: chore: [ci skip] VSync progression as an extension 2025-01-30 16:54:05 -06:00
Evan Husted 359852b5c0 UI: Change order of VSync mode changing
VSync -> VSync Off -> Custom
is now
VSync -> Custom -> VSync Off

Note that Custom only appears if it's enabled in settings. This has no change if you aren't using custom VSync.
2025-01-30 16:47:40 -06:00
Evan Husted 796674d9cf UI: Allow more freedom changing the Speed value & clamp the visible number to a sane amount of trailing digits 2025-01-30 03:30:50 -06:00
Evan Husted 4efe24a3bc misc: chore: [ci skip] forgot to make that a locale entry 2025-01-30 03:21:42 -06:00
Evan Husted 1a42d1396c UI: Rainbow cycling speed settings
Note: this setting is global, even though it appears in the settings for the individual gamepad. This is simply for consistency; you access all the rainbow stuff in one place.
2025-01-30 03:18:34 -06:00
Evan Husted 11f29361eb misc: chore: [ci skip] Log errors from TaskScheduler.UnobservedTaskException 2025-01-29 21:07:43 -06:00
Evan Husted 71d8cfd232 misc: chore: Pass rainbow color by reference in the event instead of passing around a packed int. 2025-01-29 20:51:55 -06:00
Evan Husted 023bd5f00f UI: Enable Rainbow cycling in the Settings window 2025-01-29 20:27:01 -06:00
Evan Husted 0ed7fd14ba misc: chore: [ci skip] Collapse CheckboxMenuItemStyle into the main Styles.xaml. 2025-01-29 18:59:17 -06:00
Evan Husted a624fe64b9 UI: Scanning for mods on DLC content 2025-01-29 13:33:34 -06:00
Vladimir Sokolov e02ef52069 Added --backend-threading arg for CommandLineState (#599)
Added the `--backend-threading` arg so that you can launch games via
a shortcut with modifications to this setting.
2025-01-29 12:49:36 -06:00
Barış Hamil 02026c3d38 Ability to assign hotkeys to cycle controllers for players 2025-01-29 21:49:33 +03:00
Evan Husted 707c9ef748 misc: chore: slightly improve PTC init log line 2025-01-28 22:25:01 -06:00
Evan Husted 2acc43e968 misc: chore: Use string.Empty in more places where it's snuck back 2025-01-28 22:17:11 -06:00
Evan Husted 191e158289 misc: chore: Use static instances of converters instead of using control resources 2025-01-28 22:11:48 -06:00
Evan Husted a469f3d710 UI: Remove empty StackPanel in UserSelectorDialog 2025-01-28 21:47:29 -06:00
66 changed files with 666 additions and 329 deletions
+5 -8
View File
@@ -4,6 +4,7 @@ using ARMeilleure.CodeGen.Unwinding;
using ARMeilleure.Common; using ARMeilleure.Common;
using ARMeilleure.Memory; using ARMeilleure.Memory;
using ARMeilleure.State; using ARMeilleure.State;
using Humanizer;
using Ryujinx.Common; using Ryujinx.Common;
using Ryujinx.Common.Configuration; using Ryujinx.Common.Configuration;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
@@ -924,14 +925,10 @@ namespace ARMeilleure.Translation.PTC
PtcStateChanged?.Invoke(PtcLoadingState.Loaded, _translateCount, _translateTotalCount); PtcStateChanged?.Invoke(PtcLoadingState.Loaded, _translateCount, _translateTotalCount);
if (_translateCount == _translateTotalCount) Logger.Info?.Print(LogClass.Ptc,
{ $"{_translateCount} of {_translateTotalCount} functions translated in {sw.Elapsed.TotalSeconds} seconds " +
Logger.Info?.Print(LogClass.Ptc, $"{_translateCount} of {_translateTotalCount} functions translated | Thread count: {degreeOfParallelism} in {sw.Elapsed.TotalSeconds} s"); $"| {"function".ToQuantity(_translateTotalCount - _translateCount)} blacklisted " +
} $"| Thread count: {degreeOfParallelism}");
else
{
Logger.Info?.Print(LogClass.Ptc, $"{_translateCount} of {_translateTotalCount} functions translated | {_translateTotalCount - _translateCount} function{(_translateTotalCount - _translateCount != 1 ? "s" : "")} blacklisted | Thread count: {degreeOfParallelism} in {sw.Elapsed.TotalSeconds} s");
}
Thread preSaveThread = new(PreSave) Thread preSaveThread = new(PreSave)
{ {
@@ -1,3 +1,5 @@
using System.Collections.Generic;
namespace Ryujinx.Common.Configuration.Hid namespace Ryujinx.Common.Configuration.Hid
{ {
public class KeyboardHotkeys public class KeyboardHotkeys
@@ -13,5 +15,6 @@ namespace Ryujinx.Common.Configuration.Hid
public Key VolumeDown { get; set; } public Key VolumeDown { get; set; }
public Key CustomVSyncIntervalIncrement { get; set; } public Key CustomVSyncIntervalIncrement { get; set; }
public Key CustomVSyncIntervalDecrement { get; set; } public Key CustomVSyncIntervalDecrement { get; set; }
public List<Key> CycleControllers { get; set; }
} }
} }
@@ -6,4 +6,16 @@ namespace Ryujinx.Common.Configuration
Unbounded, Unbounded,
Custom Custom
} }
public static class VSyncModeExtensions
{
public static VSyncMode Next(this VSyncMode vsync, bool customEnabled = false) =>
vsync switch
{
VSyncMode.Switch => customEnabled ? VSyncMode.Custom : VSyncMode.Unbounded,
VSyncMode.Unbounded => VSyncMode.Switch,
VSyncMode.Custom => VSyncMode.Unbounded,
_ => VSyncMode.Switch
};
}
} }
+58
View File
@@ -0,0 +1,58 @@
using Gommon;
using System.Collections.Generic;
using System.Threading;
namespace Ryujinx.Common.Helper
{
public class RefEvent<T>
{
public delegate void Handler(ref T arg);
private readonly Lock _subLock = new();
private readonly List<Handler> _subscriptions = [];
public bool HasSubscribers
{
get
{
lock (_subLock)
return _subscriptions.Count != 0;
}
}
public IReadOnlyList<Handler> Subscriptions
{
get
{
lock (_subLock)
return _subscriptions;
}
}
public void Add(Handler subscriber)
{
Guard.Require(subscriber, nameof(subscriber));
lock (_subLock)
_subscriptions.Add(subscriber);
}
public void Remove(Handler subscriber)
{
Guard.Require(subscriber, nameof(subscriber));
lock (_subLock)
_subscriptions.Remove(subscriber);
}
public void Clear()
{
lock (_subLock)
_subscriptions.Clear();
}
public void Call(ref T arg)
{
foreach (Handler subscription in Subscriptions)
subscription(ref arg);
}
}
}
+8 -3
View File
@@ -30,10 +30,11 @@ namespace Ryujinx.Common
public static readonly string[] GreatMetalTitles = public static readonly string[] GreatMetalTitles =
[ [
"010076f0049a2000", // Bayonetta "01009b500007c000", // ARMS
"0100a5c00d162000", // Cuphead "0100a5c00d162000", // Cuphead
"010023800d64a000", // Deltarune "010023800d64a000", // Deltarune
"01003a30012c0000", // LEGO City Undercover "01003a30012c0000", // LEGO City Undercover
"010048701995e000", // Luigi's Manion 2 HD
"010028600EBDA000", // Mario 3D World "010028600EBDA000", // Mario 3D World
"0100152000022000", // Mario Kart 8 Deluxe "0100152000022000", // Mario Kart 8 Deluxe
"010075a016a3a000", // Persona 4 Arena Ultimax "010075a016a3a000", // Persona 4 Arena Ultimax
@@ -48,10 +49,14 @@ namespace Ryujinx.Common
"01009bf0072d4000", // Captain Toad: Treasure Tracker "01009bf0072d4000", // Captain Toad: Treasure Tracker
"01009510001ca000", // Fast RMX "01009510001ca000", // Fast RMX
"01005CA01580E000", // Persona 5 Royale "01005CA01580E000", // Persona 5 Royale
"010015100b514000", // Super Mario Bros. Wonder
"0100000000010000", // Super Mario Odyssey "0100000000010000", // Super Mario Odyssey
//Isaac claims it has a issue in level 2, but I am not able to replicate it on my M3. More testing would be appreciated: // Further testing is appreciated, I did not test the entire game:
"010015100b514000", // Super Mario Bros. Wonder "01007300020fa000", // Astral Chain
"010076f0049a2000", // Bayonetta
"0100cf5010fec000", // Bayonetta Origins: Cereza and the Lost Demon
"0100f4300bf2c000", // New Pokemon Snap
]; ];
public static string GetDiscordGameAsset(string titleId) public static string GetDiscordGameAsset(string titleId)
+4 -3
View File
@@ -1,4 +1,5 @@
using Gommon; using Gommon;
using Ryujinx.Common.Helper;
using System; using System;
using System.Drawing; using System.Drawing;
using System.Threading; using System.Threading;
@@ -55,7 +56,7 @@ namespace Ryujinx.Common.Utilities
{ {
_color = HsbToRgb((_color.GetHue() + Speed) / 360); _color = HsbToRgb((_color.GetHue() + Speed) / 360);
_updatedHandler.Call(_color.ToArgb()); _updatedHandler.Call(ref _color);
} }
} }
@@ -67,13 +68,13 @@ namespace Ryujinx.Common.Utilities
_color = Color.Blue; _color = Color.Blue;
} }
public static event Action<int> Updated public static event RefEvent<Color>.Handler Updated
{ {
add => _updatedHandler.Add(value); add => _updatedHandler.Add(value);
remove => _updatedHandler.Remove(value); remove => _updatedHandler.Remove(value);
} }
private static readonly Event<int> _updatedHandler = new(); private static readonly RefEvent<Color> _updatedHandler = new();
private static Color HsbToRgb(float hue, float saturation = 1, float brightness = 1) private static Color HsbToRgb(float hue, float saturation = 1, float brightness = 1)
{ {
+1 -1
View File
@@ -76,7 +76,7 @@ namespace Ryujinx.Graphics.Metal
return model; return model;
} }
return ""; return string.Empty;
} }
} }
} }
@@ -218,7 +218,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Msl
foreach (MemoryDefinition memory in memories) foreach (MemoryDefinition memory in memories)
{ {
string arraySize = ""; string arraySize = string.Empty;
if ((memory.Type & AggregateType.Array) != 0) if ((memory.Type & AggregateType.Array) != 0)
{ {
arraySize = $"[{memory.ArrayLength}]"; arraySize = $"[{memory.ArrayLength}]";
@@ -240,7 +240,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Msl
BufferDefinition buffer = buffers[i]; BufferDefinition buffer = buffers[i];
bool needsPadding = buffer.Layout == BufferLayout.Std140; bool needsPadding = buffer.Layout == BufferLayout.Std140;
string fsiSuffix = !constant && fsi ? " [[raster_order_group(0)]]" : ""; string fsiSuffix = !constant && fsi ? " [[raster_order_group(0)]]" : string.Empty;
bufferDec[i] = $"{addressSpace} {Defaults.StructPrefix}_{buffer.Name}* {buffer.Name}{fsiSuffix};"; bufferDec[i] = $"{addressSpace} {Defaults.StructPrefix}_{buffer.Name}* {buffer.Name}{fsiSuffix};";
@@ -257,7 +257,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Msl
type &= ~AggregateType.Array; type &= ~AggregateType.Array;
string typeName = GetVarTypeName(type); string typeName = GetVarTypeName(type);
string arraySuffix = ""; string arraySuffix = string.Empty;
if (field.Type.HasFlag(AggregateType.Array)) if (field.Type.HasFlag(AggregateType.Array))
{ {
@@ -353,7 +353,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Msl
imageTypeName = $"array<{imageTypeName}, {image.ArrayLength}>"; imageTypeName = $"array<{imageTypeName}, {image.ArrayLength}>";
} }
string fsiSuffix = fsi ? " [[raster_order_group(0)]]" : ""; string fsiSuffix = fsi ? " [[raster_order_group(0)]]" : string.Empty;
imageDec[i] = $"{imageTypeName} {image.Name}{fsiSuffix};"; imageDec[i] = $"{imageTypeName} {image.Name}{fsiSuffix};";
} }
@@ -454,7 +454,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Msl
IoVariable.VertexIndex => "[[vertex_id]]", IoVariable.VertexIndex => "[[vertex_id]]",
// IoVariable.PointCoord => "[[point_coord]]", // IoVariable.PointCoord => "[[point_coord]]",
IoVariable.UserDefined => context.Definitions.Stage == ShaderStage.Fragment ? $"[[user(loc{ioDefinition.Location})]]" : $"[[attribute({ioDefinition.Location})]]", IoVariable.UserDefined => context.Definitions.Stage == ShaderStage.Fragment ? $"[[user(loc{ioDefinition.Location})]]" : $"[[attribute({ioDefinition.Location})]]",
_ => "" _ => string.Empty
}; };
context.AppendLine($"{type} {name} {iq}{suffix};"); context.AppendLine($"{type} {name} {iq}{suffix};");
@@ -545,7 +545,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Msl
IoVariable.FragmentOutputColor => $"[[color({ioDefinition.Location})]]", IoVariable.FragmentOutputColor => $"[[color({ioDefinition.Location})]]",
IoVariable.FragmentOutputDepth => "[[depth(any)]]", IoVariable.FragmentOutputDepth => "[[depth(any)]]",
IoVariable.ClipDistance => $"[[clip_distance]][{Defaults.TotalClipDistances}]", IoVariable.ClipDistance => $"[[clip_distance]][{Defaults.TotalClipDistances}]",
_ => "" _ => string.Empty
}; };
context.AppendLine($"{type} {name} {suffix};"); context.AppendLine($"{type} {name} {suffix};");
@@ -27,7 +27,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Msl.Instructions
inputsCount--; inputsCount--;
} }
string fieldName = ""; string fieldName = string.Empty;
switch (storageKind) switch (storageKind)
{ {
case StorageKind.ConstantBuffer: case StorageKind.ConstantBuffer:
@@ -140,7 +140,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Msl.Instructions
} }
} }
varName += fieldName; varName += fieldName;
varName += fieldHasPadding ? ".x" : ""; varName += fieldHasPadding ? ".x" : string.Empty;
if (isStore) if (isStore)
{ {
@@ -434,7 +434,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Msl.Instructions
string prefix = intCoords ? "uint" : "float"; string prefix = intCoords ? "uint" : "float";
return prefix + (count > 1 ? count : "") + "(" + coords + ")"; return prefix + (count > 1 ? count : string.Empty) + "(" + coords + ")";
} }
Append(AssemblePVector(pCount)); Append(AssemblePVector(pCount));
@@ -504,7 +504,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Msl.Instructions
} }
texCallBuilder.Append(')'); texCallBuilder.Append(')');
texCallBuilder.Append(colorIsVector ? GetMaskMultiDest(texOp.Index) : ""); texCallBuilder.Append(colorIsVector ? GetMaskMultiDest(texOp.Index) : string.Empty);
return texCallBuilder.ToString(); return texCallBuilder.ToString();
} }
@@ -558,7 +558,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Msl.Instructions
{ {
if (mask == 0x0) if (mask == 0x0)
{ {
return ""; return string.Empty;
} }
string swizzle = "."; string swizzle = ".";
@@ -15,7 +15,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Msl
if (parameters.Definitions.Stage is not (ShaderStage.Vertex or ShaderStage.Fragment or ShaderStage.Compute)) if (parameters.Definitions.Stage is not (ShaderStage.Vertex or ShaderStage.Fragment or ShaderStage.Compute))
{ {
Logger.Warning?.Print(LogClass.Gpu, $"Attempted to generate unsupported shader type {parameters.Definitions.Stage}!"); Logger.Warning?.Print(LogClass.Gpu, $"Attempted to generate unsupported shader type {parameters.Definitions.Stage}!");
return ""; return string.Empty;
} }
CodeGenContext context = new(info, parameters); CodeGenContext context = new(info, parameters);
+1 -1
View File
@@ -199,7 +199,7 @@ namespace Ryujinx.Graphics.Shader
_ => "float" _ => "float"
}; };
return $"{typeName}<{format}{(image ? ", access::read_write" : "")}>"; return $"{typeName}<{format}{(image ? ", access::read_write" : string.Empty)}>";
} }
} }
} }
+13 -3
View File
@@ -296,7 +296,7 @@ namespace Ryujinx.HLE.HOS
AddModsFromDirectory(mods, applicationDir, modMetadata); AddModsFromDirectory(mods, applicationDir, modMetadata);
} }
public static void QueryContentsDir(ModCache mods, DirectoryInfo contentsDir, ulong applicationId) public static void QueryContentsDir(ModCache mods, DirectoryInfo contentsDir, ulong applicationId, ulong[] installedDlcs)
{ {
if (!contentsDir.Exists) if (!contentsDir.Exists)
{ {
@@ -311,6 +311,16 @@ namespace Ryujinx.HLE.HOS
{ {
QueryApplicationDir(mods, applicationDir, applicationId); QueryApplicationDir(mods, applicationDir, applicationId);
} }
foreach (ulong installedDlcId in installedDlcs)
{
DirectoryInfo dlcModDir = FindApplicationDir(contentsDir, $"{installedDlcId:x16}");
if (dlcModDir != null)
{
QueryApplicationDir(mods, dlcModDir, applicationId);
}
}
} }
private static int QueryCheatsDir(ModCache mods, DirectoryInfo cheatsDir) private static int QueryCheatsDir(ModCache mods, DirectoryInfo cheatsDir)
@@ -417,7 +427,7 @@ namespace Ryujinx.HLE.HOS
{ {
foreach ((ulong applicationId, ModCache cache) in modCaches) foreach ((ulong applicationId, ModCache cache) in modCaches)
{ {
QueryContentsDir(cache, searchDir, applicationId); QueryContentsDir(cache, searchDir, applicationId, Array.Empty<ulong>());
} }
return true; return true;
@@ -679,7 +689,7 @@ namespace Ryujinx.HLE.HOS
{ {
using (MD5 md5 = MD5.Create()) using (MD5 md5 = MD5.Create())
{ {
modLoadResult.Hash += BitConverter.ToString(md5.ComputeHash(tempHash.ToBytes())).Replace("-", "").ToLowerInvariant(); modLoadResult.Hash += BitConverter.ToString(md5.ComputeHash(tempHash.ToBytes())).Replace("-", string.Empty).ToLowerInvariant();
} }
} }
@@ -121,7 +121,7 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator.LdnRyu
private void UpdatePassphraseIfNeeded() private void UpdatePassphraseIfNeeded()
{ {
string passphrase = _config.MultiplayerLdnPassphrase ?? ""; string passphrase = _config.MultiplayerLdnPassphrase ?? string.Empty;
if (passphrase != _passphrase) if (passphrase != _passphrase)
{ {
_passphrase = passphrase; _passphrase = passphrase;
@@ -88,7 +88,7 @@ namespace Ryujinx.HLE.Loaders.Processes
bool isFirmwareApplication = ProgramId <= 0x0100000000007FFF; bool isFirmwareApplication = ProgramId <= 0x0100000000007FFF;
string name = !isFirmware string name = !isFirmware
? (isFirmwareApplication ? "Firmware Application " : "") + (!string.IsNullOrWhiteSpace(Name) ? Name : "<Unknown Name>") ? (isFirmwareApplication ? "Firmware Application " : string.Empty) + (!string.IsNullOrWhiteSpace(Name) ? Name : "<Unknown Name>")
: "Firmware"; : "Firmware";
// TODO: LibHac npdm currently doesn't support version field. // TODO: LibHac npdm currently doesn't support version field.
+2 -4
View File
@@ -2,8 +2,6 @@ using Ryujinx.Common.Configuration.Hid;
using Ryujinx.Common.Configuration.Hid.Controller; using Ryujinx.Common.Configuration.Hid.Controller;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.Common.Utilities; using Ryujinx.Common.Utilities;
using Ryujinx.HLE.HOS.Services.Hid;
using SDL2;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Numerics; using System.Numerics;
@@ -12,7 +10,7 @@ using static SDL2.SDL;
namespace Ryujinx.Input.SDL2 namespace Ryujinx.Input.SDL2
{ {
class SDL2Gamepad : IGamepad public class SDL2Gamepad : IGamepad
{ {
private bool HasConfiguration => _configuration != null; private bool HasConfiguration => _configuration != null;
@@ -113,7 +111,7 @@ namespace Ryujinx.Input.SDL2
byte blue = packedRgb > 0 ? (byte)(packedRgb % 256) : (byte)0; byte blue = packedRgb > 0 ? (byte)(packedRgb % 256) : (byte)0;
if (SDL_GameControllerSetLED(_gamepadHandle, red, green, blue) != 0) if (SDL_GameControllerSetLED(_gamepadHandle, red, green, blue) != 0)
Logger.Error?.Print(LogClass.Hid, "LED is not supported on this game controller."); Logger.Error?.Print(LogClass.Hid, "LED setting failed; probably in the middle of disconnecting.");
} }
private GamepadFeaturesFlag GetFeaturesFlag() private GamepadFeaturesFlag GetFeaturesFlag()
+27 -23
View File
@@ -40,6 +40,7 @@ using Ryujinx.HLE;
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;
using Ryujinx.HLE.HOS.Services.Hid;
using Ryujinx.HLE.HOS.SystemState; using Ryujinx.HLE.HOS.SystemState;
using Ryujinx.Input; using Ryujinx.Input;
using Ryujinx.Input.HLE; using Ryujinx.Input.HLE;
@@ -49,6 +50,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.IO; using System.IO;
using System.Linq;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
@@ -319,31 +321,12 @@ namespace Ryujinx.Ava
public void VSyncModeToggle() public void VSyncModeToggle()
{ {
VSyncMode oldVSyncMode = Device.VSyncMode; VSyncMode oldVSyncMode = Device.VSyncMode;
VSyncMode newVSyncMode = VSyncMode.Switch;
bool customVSyncIntervalEnabled = ConfigurationState.Instance.Graphics.EnableCustomVSyncInterval.Value; bool customVSyncIntervalEnabled = ConfigurationState.Instance.Graphics.EnableCustomVSyncInterval.Value;
switch (oldVSyncMode) UpdateVSyncMode(this, new ReactiveEventArgs<VSyncMode>(
{ oldVSyncMode,
case VSyncMode.Switch: oldVSyncMode.Next(customVSyncIntervalEnabled))
newVSyncMode = VSyncMode.Unbounded; );
break;
case VSyncMode.Unbounded:
if (customVSyncIntervalEnabled)
{
newVSyncMode = VSyncMode.Custom;
}
else
{
newVSyncMode = VSyncMode.Switch;
}
break;
case VSyncMode.Custom:
newVSyncMode = VSyncMode.Switch;
break;
}
UpdateVSyncMode(this, new ReactiveEventArgs<VSyncMode>(oldVSyncMode, newVSyncMode));
} }
private void UpdateCustomVSyncIntervalValue(object sender, ReactiveEventArgs<int> e) private void UpdateCustomVSyncIntervalValue(object sender, ReactiveEventArgs<int> e)
@@ -1325,6 +1308,18 @@ namespace Ryujinx.Ava
_viewModel.Volume = Device.GetVolume(); _viewModel.Volume = Device.GetVolume();
break; break;
case KeyboardHotkeyState.CycleControllersPlayer1:
case KeyboardHotkeyState.CycleControllersPlayer2:
case KeyboardHotkeyState.CycleControllersPlayer3:
case KeyboardHotkeyState.CycleControllersPlayer4:
case KeyboardHotkeyState.CycleControllersPlayer5:
case KeyboardHotkeyState.CycleControllersPlayer6:
case KeyboardHotkeyState.CycleControllersPlayer7:
case KeyboardHotkeyState.CycleControllersPlayer8:
var player = currentHotkeyState - KeyboardHotkeyState.CycleControllersPlayer1;
var ivm = new UI.ViewModels.Input.InputViewModel();
Dispatcher.UIThread.Invoke(() => ivm.CyclePlayerDevice(player));
break;
case KeyboardHotkeyState.None: case KeyboardHotkeyState.None:
(_keyboardInterface as AvaloniaKeyboard).Clear(); (_keyboardInterface as AvaloniaKeyboard).Clear();
break; break;
@@ -1407,6 +1402,15 @@ namespace Ryujinx.Ava
state = KeyboardHotkeyState.CustomVSyncIntervalDecrement; state = KeyboardHotkeyState.CustomVSyncIntervalDecrement;
} }
foreach (var cycle in ConfigurationState.Instance.Hid.Hotkeys.Value.CycleControllers?.Select((value, index) => (value, index)) ?? [])
{
if (_keyboardInterface.IsPressed((Key)cycle.value))
{
state = KeyboardHotkeyState.CycleControllersPlayer1 + cycle.index;
break;
}
}
return state; return state;
} }
} }
@@ -1,13 +0,0 @@
<Styles xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style Selector="MenuItem.withCheckbox Viewbox#PART_IconPresenter">
<Setter Property="MaxHeight" Value="36" />
<Setter Property="MinHeight" Value="36" />
<Setter Property="MaxWidth" Value="36" />
<Setter Property="MinWidth" Value="36" />
</Style>
<Style Selector="MenuItem.withCheckbox ContentPresenter#PART_HeaderPresenter">
<Setter Property="Padding" Value="-10,0,0,0" />
</Style>
</Styles>
+9
View File
@@ -218,6 +218,15 @@
<Setter Property="BorderBrush" <Setter Property="BorderBrush"
Value="{DynamicResource ThemeControlBorderColor}" /> Value="{DynamicResource ThemeControlBorderColor}" />
</Style> </Style>
<Style Selector="MenuItem.withCheckbox Viewbox#PART_IconPresenter">
<Setter Property="MaxHeight" Value="36" />
<Setter Property="MinHeight" Value="36" />
<Setter Property="MaxWidth" Value="36" />
<Setter Property="MinWidth" Value="36" />
</Style>
<Style Selector="MenuItem.withCheckbox ContentPresenter#PART_HeaderPresenter">
<Setter Property="Padding" Value="-10,0,0,0" />
</Style>
<Style Selector="TabItem > ScrollViewer"> <Style Selector="TabItem > ScrollViewer">
<Setter Property="Background" <Setter Property="Background"
Value="{DynamicResource ThemeBackgroundColor}" /> Value="{DynamicResource ThemeBackgroundColor}" />
+50
View File
@@ -5347,6 +5347,31 @@
"zh_TW": "啟用警告日誌" "zh_TW": "啟用警告日誌"
} }
}, },
{
"ID": "SettingsTabHotkeysCycleControllers",
"Translations": {
"ar_SA": "",
"de_DE": "",
"el_GR": "",
"en_US": "Cycle Controllers",
"es_ES": "",
"fr_FR": "",
"he_IL": "",
"it_IT": "",
"ja_JP": "",
"ko_KR": "",
"no_NO": "",
"pl_PL": "",
"pt_BR": "",
"ru_RU": "",
"sv_SE": "",
"th_TH": "",
"tr_TR": "",
"uk_UA": "",
"zh_CN": "",
"zh_TW": ""
}
},
{ {
"ID": "SettingsTabLoggingEnableErrorLogs", "ID": "SettingsTabLoggingEnableErrorLogs",
"Translations": { "Translations": {
@@ -7747,6 +7772,31 @@
"zh_TW": "" "zh_TW": ""
} }
}, },
{
"ID": "ControllerSettingsLedColorRainbowSpeed",
"Translations": {
"ar_SA": "",
"de_DE": "",
"el_GR": "",
"en_US": "Rainbow Speed",
"es_ES": "",
"fr_FR": "",
"he_IL": "",
"it_IT": "",
"ja_JP": "",
"ko_KR": "",
"no_NO": "",
"pl_PL": "",
"pt_BR": "",
"ru_RU": "",
"sv_SE": "",
"th_TH": "",
"tr_TR": "",
"uk_UA": "",
"zh_CN": "",
"zh_TW": ""
}
},
{ {
"ID": "ControllerSettingsLedColor", "ID": "ControllerSettingsLedColor",
"Translations": { "Translations": {
@@ -14,5 +14,13 @@ namespace Ryujinx.Ava.Common
VolumeDown, VolumeDown,
CustomVSyncIntervalIncrement, CustomVSyncIntervalIncrement,
CustomVSyncIntervalDecrement, CustomVSyncIntervalDecrement,
CycleControllersPlayer1,
CycleControllersPlayer2,
CycleControllersPlayer3,
CycleControllersPlayer4,
CycleControllersPlayer5,
CycleControllersPlayer6,
CycleControllersPlayer7,
CycleControllersPlayer8
} }
} }
+14 -2
View File
@@ -112,8 +112,12 @@ namespace Ryujinx.Ava
// Hook unhandled exception and process exit events. // Hook unhandled exception and process exit events.
AppDomain.CurrentDomain.UnhandledException += (sender, e) AppDomain.CurrentDomain.UnhandledException += (sender, e)
=> ProcessUnhandledException(sender, e.ExceptionObject as Exception, e.IsTerminating); => ProcessUnhandledException(sender, e.ExceptionObject as Exception, e.IsTerminating);
TaskScheduler.UnobservedTaskException += (sender, e)
=> ProcessUnhandledException(sender, e.Exception, false);
AppDomain.CurrentDomain.ProcessExit += (_, _) => Exit(); AppDomain.CurrentDomain.ProcessExit += (_, _) => Exit();
// Setup base data directory. // Setup base data directory.
AppDataManager.Initialize(CommandLineState.BaseDirPathArg); AppDataManager.Initialize(CommandLineState.BaseDirPathArg);
@@ -206,6 +210,16 @@ namespace Ryujinx.Ava
_ => ConfigurationState.Instance.Graphics.GraphicsBackend _ => ConfigurationState.Instance.Graphics.GraphicsBackend
}; };
// Check if backend threading was overridden
if (CommandLineState.OverrideBackendThreading is not null)
ConfigurationState.Instance.Graphics.BackendThreading.Value = CommandLineState.OverrideBackendThreading.ToLower() switch
{
"auto" => BackendThreading.Auto,
"off" => BackendThreading.Off,
"on" => BackendThreading.On,
_ => ConfigurationState.Instance.Graphics.BackendThreading
};
// Check if docked mode was overriden. // Check if docked mode was overriden.
if (CommandLineState.OverrideDockedMode.HasValue) if (CommandLineState.OverrideDockedMode.HasValue)
ConfigurationState.Instance.System.EnableDockedMode.Value = CommandLineState.OverrideDockedMode.Value; ConfigurationState.Instance.System.EnableDockedMode.Value = CommandLineState.OverrideDockedMode.Value;
@@ -273,8 +287,6 @@ namespace Ryujinx.Ava
} }
if (isTerminating) if (isTerminating)
Exit(); Exit();
} }
-3
View File
@@ -123,13 +123,11 @@
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
</AvaloniaResource> </AvaloniaResource>
<AvaloniaResource Include="Assets\Styles\Styles.xaml" /> <AvaloniaResource Include="Assets\Styles\Styles.xaml" />
<AvaloniaResource Include="Assets\Styles\CheckboxMenuItemStyle.axaml" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Remove="Assets\locales.json" /> <None Remove="Assets\locales.json" />
<None Remove="Assets\Styles\Themes.xaml" /> <None Remove="Assets\Styles\Themes.xaml" />
<None Remove="Assets\Styles\CheckboxMenuItemStyle.xaml" />
<None Remove="Assets\Icons\Controller_JoyConLeft.svg" /> <None Remove="Assets\Icons\Controller_JoyConLeft.svg" />
<None Remove="Assets\Icons\Controller_JoyConPair.svg" /> <None Remove="Assets\Icons\Controller_JoyConPair.svg" />
<None Remove="Assets\Icons\Controller_JoyConRight.svg" /> <None Remove="Assets\Icons\Controller_JoyConRight.svg" />
@@ -151,7 +149,6 @@
</EmbeddedResource> </EmbeddedResource>
<EmbeddedResource Include="Assets\locales.json" /> <EmbeddedResource Include="Assets\locales.json" />
<EmbeddedResource Include="Assets\Styles\Styles.xaml" /> <EmbeddedResource Include="Assets\Styles\Styles.xaml" />
<EmbeddedResource Include="Assets\Styles\CheckboxMenuItemStyle.axaml" />
<EmbeddedResource Include="Assets\Icons\Controller_JoyConLeft.svg" /> <EmbeddedResource Include="Assets\Icons\Controller_JoyConLeft.svg" />
<EmbeddedResource Include="Assets\Icons\Controller_JoyConPair.svg" /> <EmbeddedResource Include="Assets\Icons\Controller_JoyConPair.svg" />
<EmbeddedResource Include="Assets\Icons\Controller_JoyConRight.svg" /> <EmbeddedResource Include="Assets\Icons\Controller_JoyConRight.svg" />
-1
View File
@@ -16,6 +16,5 @@
<Application.Styles> <Application.Styles>
<sty:FluentAvaloniaTheme PreferUserAccentColor="True" PreferSystemTheme="False" /> <sty:FluentAvaloniaTheme PreferUserAccentColor="True" PreferSystemTheme="False" />
<StyleInclude Source="/Assets/Styles/Styles.xaml" /> <StyleInclude Source="/Assets/Styles/Styles.xaml" />
<StyleInclude Source="/Assets/Styles/CheckboxMenuItemStyle.axaml"/>
</Application.Styles> </Application.Styles>
</Application> </Application>
+1 -13
View File
@@ -13,11 +13,6 @@
mc:Ignorable="d" mc:Ignorable="d"
Focusable="True" Focusable="True"
x:DataType="viewModels:UserSelectorDialogViewModel"> x:DataType="viewModels:UserSelectorDialogViewModel">
<UserControl.Resources>
<helpers:BitmapArrayValueConverter x:Key="ByteImage" />
</UserControl.Resources>
<Design.DataContext> <Design.DataContext>
<viewModels:UserSelectorDialogViewModel /> <viewModels:UserSelectorDialogViewModel />
</Design.DataContext> </Design.DataContext>
@@ -80,7 +75,7 @@
Height="96" Height="96"
HorizontalAlignment="Stretch" HorizontalAlignment="Stretch"
VerticalAlignment="Top" VerticalAlignment="Top"
Source="{Binding Image, Converter={StaticResource ByteImage}}" /> Source="{Binding Image, Converter={x:Static helpers:BitmapArrayValueConverter.Instance}}" />
<TextBlock <TextBlock
HorizontalAlignment="Stretch" HorizontalAlignment="Stretch"
MaxWidth="90" MaxWidth="90"
@@ -110,12 +105,5 @@
</ListBox> </ListBox>
</Border> </Border>
<StackPanel
Grid.Row="1"
Margin="0 24 0 0"
HorizontalAlignment="Left"
Orientation="Horizontal"
Spacing="10">
</StackPanel>
</Grid> </Grid>
</UserControl> </UserControl>
@@ -128,7 +128,11 @@ namespace Ryujinx.Ava.UI.Controls
public async void OpenModManager_Click(object sender, RoutedEventArgs args) public async void OpenModManager_Click(object sender, RoutedEventArgs args)
{ {
if (sender is MenuItem { DataContext: MainWindowViewModel { SelectedApplication: not null } viewModel }) if (sender is MenuItem { DataContext: MainWindowViewModel { SelectedApplication: not null } viewModel })
await ModManagerWindow.Show(viewModel.SelectedApplication.Id, viewModel.SelectedApplication.Name); await ModManagerWindow.Show(
viewModel.SelectedApplication.Id,
viewModel.SelectedApplication.IdBase,
viewModel.ApplicationLibrary,
viewModel.SelectedApplication.Name);
} }
public async void PurgePtcCache_Click(object sender, RoutedEventArgs args) public async void PurgePtcCache_Click(object sender, RoutedEventArgs args)
@@ -13,9 +13,6 @@
mc:Ignorable="d" mc:Ignorable="d"
xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels" xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
x:DataType="viewModels:MainWindowViewModel"> x:DataType="viewModels:MainWindowViewModel">
<UserControl.Resources>
<helpers:BitmapArrayValueConverter x:Key="ByteImage" />
</UserControl.Resources>
<Grid> <Grid>
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition Height="*" /> <RowDefinition Height="*" />
@@ -68,7 +65,7 @@
Grid.Row="0" Grid.Row="0"
HorizontalAlignment="Stretch" HorizontalAlignment="Stretch"
VerticalAlignment="Top" VerticalAlignment="Top"
Source="{Binding Icon, Converter={StaticResource ByteImage}}" /> Source="{Binding Icon, Converter={x:Static helpers:BitmapArrayValueConverter.Instance}}" />
<Panel <Panel
Grid.Row="1" Grid.Row="1"
Height="50" Height="50"
@@ -12,9 +12,6 @@
mc:Ignorable="d" mc:Ignorable="d"
xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels" xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
x:DataType="viewModels:MainWindowViewModel"> x:DataType="viewModels:MainWindowViewModel">
<UserControl.Resources>
<helpers:BitmapArrayValueConverter x:Key="ByteImage" />
</UserControl.Resources>
<Grid> <Grid>
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition Height="*" /> <RowDefinition Height="*" />
@@ -62,7 +59,7 @@
Classes.large="{Binding $parent[UserControl].((viewModels:MainWindowViewModel)DataContext).IsGridLarge}" Classes.large="{Binding $parent[UserControl].((viewModels:MainWindowViewModel)DataContext).IsGridLarge}"
Classes.normal="{Binding $parent[UserControl].((viewModels:MainWindowViewModel)DataContext).IsGridMedium}" Classes.normal="{Binding $parent[UserControl].((viewModels:MainWindowViewModel)DataContext).IsGridMedium}"
Classes.small="{Binding $parent[UserControl].((viewModels:MainWindowViewModel)DataContext).IsGridSmall}" Classes.small="{Binding $parent[UserControl].((viewModels:MainWindowViewModel)DataContext).IsGridSmall}"
Source="{Binding Icon, Converter={StaticResource ByteImage}}" /> Source="{Binding Icon, Converter={x:Static helpers:BitmapArrayValueConverter.Instance}}" />
<Border <Border
Grid.Column="2" Grid.Column="2"
Margin="0,0,5,0" Margin="0,0,5,0"
@@ -9,7 +9,7 @@ namespace Ryujinx.Ava.UI.Helpers
{ {
internal class BitmapArrayValueConverter : IValueConverter internal class BitmapArrayValueConverter : IValueConverter
{ {
public static BitmapArrayValueConverter Instance = new(); public static readonly BitmapArrayValueConverter Instance = new();
public object Convert(object value, Type targetType, object parameter, CultureInfo culture) public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{ {
@@ -11,7 +11,7 @@ namespace Ryujinx.Ava.UI.Helpers
{ {
internal class DownloadableContentLabelConverter : IMultiValueConverter internal class DownloadableContentLabelConverter : IMultiValueConverter
{ {
public static DownloadableContentLabelConverter Instance = new(); public static readonly DownloadableContentLabelConverter Instance = new();
public object Convert(IList<object> values, Type targetType, object parameter, CultureInfo culture) public object Convert(IList<object> values, Type targetType, object parameter, CultureInfo culture)
{ {
@@ -10,7 +10,7 @@ namespace Ryujinx.Ava.UI.Helpers
{ {
internal class KeyValueConverter : IValueConverter internal class KeyValueConverter : IValueConverter
{ {
public static KeyValueConverter Instance = new(); public static readonly KeyValueConverter Instance = new();
private static readonly Dictionary<Key, LocaleKeys> _keysMap = new() private static readonly Dictionary<Key, LocaleKeys> _keysMap = new()
{ {
@@ -1,6 +1,5 @@
using Avalonia.Data.Converters; using Avalonia.Data.Converters;
using Avalonia.Markup.Xaml; using Avalonia.Markup.Xaml;
using Ryujinx.Ava.Common.Locale;
using Ryujinx.Ava.Utilities.AppLibrary; using Ryujinx.Ava.Utilities.AppLibrary;
using System; using System;
using System.Globalization; using System.Globalization;
@@ -19,15 +18,10 @@ namespace Ryujinx.Ava.UI.Helpers
{ {
return $"Hosted Games: {applicationData.GameCount}\nOnline Players: {applicationData.PlayerCount}"; return $"Hosted Games: {applicationData.GameCount}\nOnline Players: {applicationData.PlayerCount}";
} }
else }
{
return ""; return "";
}
}
else
{
return "";
}
} }
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
@@ -11,7 +11,7 @@ namespace Ryujinx.Ava.UI.Helpers
{ {
internal class TitleUpdateLabelConverter : IMultiValueConverter internal class TitleUpdateLabelConverter : IMultiValueConverter
{ {
public static TitleUpdateLabelConverter Instance = new(); public static readonly TitleUpdateLabelConverter Instance = new();
public object Convert(IList<object> values, Type targetType, object parameter, CultureInfo culture) public object Convert(IList<object> values, Type targetType, object parameter, CultureInfo culture)
{ {
@@ -12,7 +12,7 @@ namespace Ryujinx.Ava.UI.Helpers
internal class XCITrimmerFileSpaceSavingsConverter : IValueConverter internal class XCITrimmerFileSpaceSavingsConverter : IValueConverter
{ {
private const long _bytesPerMB = 1024 * 1024; private const long _bytesPerMB = 1024 * 1024;
public static XCITrimmerFileSpaceSavingsConverter Instance = new(); public static readonly XCITrimmerFileSpaceSavingsConverter Instance = new();
public object Convert(object value, Type targetType, object parameter, CultureInfo culture) public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{ {
@@ -1,6 +1,11 @@
using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.ComponentModel;
using DynamicData;
using Ryujinx.Ava.UI.Helpers;
using Ryujinx.Ava.UI.ViewModels; using Ryujinx.Ava.UI.ViewModels;
using Ryujinx.Common.Configuration.Hid; using Ryujinx.Common.Configuration.Hid;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows.Input;
namespace Ryujinx.Ava.UI.Models.Input namespace Ryujinx.Ava.UI.Models.Input
{ {
@@ -28,8 +33,15 @@ namespace Ryujinx.Ava.UI.Models.Input
[ObservableProperty] private Key _customVSyncIntervalDecrement; [ObservableProperty] private Key _customVSyncIntervalDecrement;
public ObservableCollection<CycleController> CycleControllers { get; set; } = new ObservableCollection<CycleController>();
public ICommand AddCycleController { get; set; }
public ICommand RemoveCycleController { get; set; }
public bool CanRemoveCycleController => CycleControllers.Count > 0 && CycleControllers.Count < 8;
public HotkeyConfig(KeyboardHotkeys config) public HotkeyConfig(KeyboardHotkeys config)
{ {
AddCycleController = MiniCommand.Create(() => CycleControllers.Add(new CycleController(CycleControllers.Count + 1, Key.Unbound)));
RemoveCycleController = MiniCommand.Create(() => CycleControllers.Remove(CycleControllers.Last()));
if (config == null) if (config == null)
return; return;
@@ -44,6 +56,7 @@ namespace Ryujinx.Ava.UI.Models.Input
VolumeDown = config.VolumeDown; VolumeDown = config.VolumeDown;
CustomVSyncIntervalIncrement = config.CustomVSyncIntervalIncrement; CustomVSyncIntervalIncrement = config.CustomVSyncIntervalIncrement;
CustomVSyncIntervalDecrement = config.CustomVSyncIntervalDecrement; CustomVSyncIntervalDecrement = config.CustomVSyncIntervalDecrement;
CycleControllers.AddRange((config.CycleControllers ?? []).Select((x, i) => new CycleController(i + 1, x)));
} }
public KeyboardHotkeys GetConfig() => public KeyboardHotkeys GetConfig() =>
@@ -60,6 +73,7 @@ namespace Ryujinx.Ava.UI.Models.Input
VolumeDown = VolumeDown, VolumeDown = VolumeDown,
CustomVSyncIntervalIncrement = CustomVSyncIntervalIncrement, CustomVSyncIntervalIncrement = CustomVSyncIntervalIncrement,
CustomVSyncIntervalDecrement = CustomVSyncIntervalDecrement, CustomVSyncIntervalDecrement = CustomVSyncIntervalDecrement,
CycleControllers = CycleControllers.Select(x => x.Hotkey).ToList()
}; };
} }
} }
+6 -1
View File
@@ -1,5 +1,5 @@
using Ryujinx.Ava.UI.ViewModels; using Ryujinx.Ava.UI.ViewModels;
using System.IO; using System.Globalization;
namespace Ryujinx.Ava.UI.Models namespace Ryujinx.Ava.UI.Models
{ {
@@ -21,6 +21,11 @@ namespace Ryujinx.Ava.UI.Models
public string Path { get; } public string Path { get; }
public string Name { get; } public string Name { get; }
public string FormattedName =>
InSd && ulong.TryParse(Name, NumberStyles.HexNumber, null, out ulong applicationId)
? $"Atmosphère: {System.IO.Path.GetFileNameWithoutExtension(RyujinxApp.MainWindow.ApplicationLibrary.GetNameForApplicationId(applicationId))}"
: Name;
public ModModel(string path, string name, bool enabled, bool inSd) public ModModel(string path, string name, bool enabled, bool inSd)
{ {
Path = path; Path = path;
@@ -0,0 +1,48 @@
using Ryujinx.Ava.Common.Locale;
using Ryujinx.Common.Configuration.Hid;
namespace Ryujinx.Ava.UI.ViewModels
{
public class CycleController : BaseModel
{
private string _player;
private Key _hotkey;
public string Player
{
get => _player;
set
{
_player = value;
OnPropertyChanged(nameof(Player));
}
}
public Key Hotkey
{
get => _hotkey;
set
{
_hotkey = value;
OnPropertyChanged(nameof(Hotkey));
}
}
public CycleController(int v, Key x)
{
Player = v switch
{
1 => LocaleManager.Instance[LocaleKeys.ControllerSettingsPlayer1],
2 => LocaleManager.Instance[LocaleKeys.ControllerSettingsPlayer2],
3 => LocaleManager.Instance[LocaleKeys.ControllerSettingsPlayer3],
4 => LocaleManager.Instance[LocaleKeys.ControllerSettingsPlayer4],
5 => LocaleManager.Instance[LocaleKeys.ControllerSettingsPlayer5],
6 => LocaleManager.Instance[LocaleKeys.ControllerSettingsPlayer6],
7 => LocaleManager.Instance[LocaleKeys.ControllerSettingsPlayer7],
8 => LocaleManager.Instance[LocaleKeys.ControllerSettingsPlayer8],
_ => LocaleManager.Instance[LocaleKeys.ControllerSettingsPlayer] + " " + v
};
Hotkey = x;
}
}
}
@@ -1,11 +1,10 @@
using Avalonia.Svg.Skia; using Avalonia.Svg.Skia;
using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using FluentAvalonia.UI.Controls;
using Ryujinx.Ava.UI.Helpers;
using Ryujinx.Ava.UI.Models.Input; using Ryujinx.Ava.UI.Models.Input;
using Ryujinx.Ava.UI.Views.Input; using Ryujinx.Ava.UI.Views.Input;
using Ryujinx.Common.Utilities;
using Ryujinx.UI.Views.Input; using Ryujinx.UI.Views.Input;
using System.Drawing;
namespace Ryujinx.Ava.UI.ViewModels.Input namespace Ryujinx.Ava.UI.ViewModels.Input
{ {
@@ -48,6 +47,23 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
ParentModel = model; ParentModel = model;
model.NotifyChangesEvent += OnParentModelChanged; model.NotifyChangesEvent += OnParentModelChanged;
OnParentModelChanged(); OnParentModelChanged();
config.PropertyChanged += (_, args) =>
{
if (args.PropertyName is nameof(Config.UseRainbowLed))
{
if (Config is { UseRainbowLed: true, TurnOffLed: false, EnableLedChanging: true })
Rainbow.Updated += (ref Color color) => ParentModel.SelectedGamepad.SetLed((uint)color.ToArgb());
else
{
Rainbow.Reset();
if (Config.TurnOffLed)
ParentModel.SelectedGamepad.ClearLed();
else
ParentModel.SelectedGamepad.SetLed(Config.LedColor.ToUInt32());
}
}
};
Config = config; Config = config;
} }
@@ -23,6 +23,7 @@ using Ryujinx.Input;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.Drawing;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Text.Json; using System.Text.Json;
@@ -63,7 +64,13 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
get => _selectedGamepad; get => _selectedGamepad;
private set private set
{ {
Rainbow.Reset();
_selectedGamepad = value; _selectedGamepad = value;
if (ConfigViewModel is ControllerInputViewModel { Config.UseRainbowLed: true })
Rainbow.Updated += (ref Color color) => _selectedGamepad.SetLed((uint)color.ToArgb());
OnPropertiesChanged(nameof(HasLed), nameof(CanClearLed)); OnPropertiesChanged(nameof(HasLed), nameof(CanClearLed));
} }
} }
@@ -890,5 +897,13 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
AvaloniaKeyboardDriver.Dispose(); AvaloniaKeyboardDriver.Dispose();
} }
public void CyclePlayerDevice(int player)
{
LoadDevices();
PlayerId = (PlayerIndex)player;
Device = (Device + 1) % Devices.Count;
Save();
}
} }
} }
@@ -1,7 +1,13 @@
using Avalonia.Media; using Avalonia.Media;
using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input; using CommunityToolkit.Mvvm.Input;
using Gommon;
using Humanizer;
using Ryujinx.Ava.UI.Helpers; using Ryujinx.Ava.UI.Helpers;
using Ryujinx.Ava.Utilities.Configuration;
using System;
using System.Globalization;
using System.Linq;
namespace Ryujinx.Ava.UI.ViewModels.Input namespace Ryujinx.Ava.UI.ViewModels.Input
{ {
@@ -22,6 +28,19 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
[ObservableProperty] private bool _enableLedChanging; [ObservableProperty] private bool _enableLedChanging;
[ObservableProperty] private Color _ledColor; [ObservableProperty] private Color _ledColor;
public string RainbowSpeedText => RainbowSpeed.ToString(CultureInfo.CurrentCulture).Truncate(4, string.Empty);
public float RainbowSpeed
{
get => ConfigurationState.Instance.Hid.RainbowSpeed;
set
{
ConfigurationState.Instance.Hid.RainbowSpeed.Value = value;
OnPropertyChanged();
OnPropertyChanged(nameof(RainbowSpeedText));
}
}
public bool ShowLedColorPicker => !TurnOffLed && !UseRainbowLed; public bool ShowLedColorPicker => !TurnOffLed && !UseRainbowLed;
private bool _turnOffLed; private bool _turnOffLed;
@@ -7,6 +7,7 @@ using Gommon;
using Ryujinx.Ava.Common.Locale; using Ryujinx.Ava.Common.Locale;
using Ryujinx.Ava.UI.Helpers; using Ryujinx.Ava.UI.Helpers;
using Ryujinx.Ava.UI.Models; using Ryujinx.Ava.UI.Models;
using Ryujinx.Ava.Utilities.AppLibrary;
using Ryujinx.Common.Configuration; using Ryujinx.Common.Configuration;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.Common.Utilities; using Ryujinx.Common.Utilities;
@@ -29,6 +30,7 @@ namespace Ryujinx.Ava.UI.ViewModels
private string _search; private string _search;
private readonly ulong _applicationId; private readonly ulong _applicationId;
private readonly ulong[] _installedDlcIds;
private readonly IStorageProvider _storageProvider; private readonly IStorageProvider _storageProvider;
private static readonly ModMetadataJsonSerializerContext _serializerContext = new(JsonHelper.GetDefaultSerializerOptions()); private static readonly ModMetadataJsonSerializerContext _serializerContext = new(JsonHelper.GetDefaultSerializerOptions());
@@ -61,18 +63,23 @@ namespace Ryujinx.Ava.UI.ViewModels
get => string.Format(LocaleManager.Instance[LocaleKeys.ModWindowHeading], Mods.Count); get => string.Format(LocaleManager.Instance[LocaleKeys.ModWindowHeading], Mods.Count);
} }
public ModManagerViewModel(ulong applicationId) public ModManagerViewModel(ulong applicationId, ulong applicationIdBase, ApplicationLibrary appLibrary)
{ {
_applicationId = applicationId; _applicationId = applicationId;
_installedDlcIds = appLibrary.DownloadableContents.Keys
.Where(x => x.TitleIdBase == applicationIdBase)
.Select(x => x.TitleId)
.ToArray();
_modJsonPath = Path.Combine(AppDataManager.GamesDirPath, applicationId.ToString("x16"), "mods.json"); _modJsonPath = Path.Combine(AppDataManager.GamesDirPath, applicationId.ToString("x16"), "mods.json");
_storageProvider = RyujinxApp.MainWindow.StorageProvider; _storageProvider = RyujinxApp.MainWindow.StorageProvider;
LoadMods(applicationId); LoadMods(applicationId, _installedDlcIds);
} }
private void LoadMods(ulong applicationId) private void LoadMods(ulong applicationId, ulong[] installedDlcIds)
{ {
Mods.Clear(); Mods.Clear();
SelectedMods.Clear(); SelectedMods.Clear();
@@ -84,7 +91,7 @@ namespace Ryujinx.Ava.UI.ViewModels
bool inSd = path == ModLoader.GetSdModsBasePath(); bool inSd = path == ModLoader.GetSdModsBasePath();
ModLoader.ModCache modCache = new(); ModLoader.ModCache modCache = new();
ModLoader.QueryContentsDir(modCache, new DirectoryInfo(Path.Combine(path, "contents")), applicationId); ModLoader.QueryContentsDir(modCache, new DirectoryInfo(Path.Combine(path, "contents")), applicationId, _installedDlcIds);
foreach (ModLoader.Mod<DirectoryInfo> mod in modCache.RomfsDirs) foreach (ModLoader.Mod<DirectoryInfo> mod in modCache.RomfsDirs)
{ {
@@ -278,7 +285,7 @@ namespace Ryujinx.Ava.UI.ViewModels
File.Copy(file, file.Replace(directory.Parent.ToString(), destinationDir), true); File.Copy(file, file.Replace(directory.Parent.ToString(), destinationDir), true);
} }
LoadMods(_applicationId); LoadMods(_applicationId, _installedDlcIds);
} }
public async void Add() public async void Add()
@@ -20,9 +20,6 @@
<Design.DataContext> <Design.DataContext>
<viewModels:ControllerInputViewModel /> <viewModels:ControllerInputViewModel />
</Design.DataContext> </Design.DataContext>
<UserControl.Resources>
<helpers:KeyValueConverter x:Key="Key" />
</UserControl.Resources>
<UserControl.Styles> <UserControl.Styles>
<Style Selector="ToggleButton"> <Style Selector="ToggleButton">
<Setter Property="Width" Value="90" /> <Setter Property="Width" Value="90" />
@@ -78,7 +75,7 @@
TextAlignment="Center" /> TextAlignment="Center" />
<ToggleButton Name="ButtonZl"> <ToggleButton Name="ButtonZl">
<TextBlock <TextBlock
Text="{Binding Config.ButtonZl, Converter={StaticResource Key}}" Text="{Binding Config.ButtonZl, Converter={x:Static helpers:KeyValueConverter.Instance}}"
TextAlignment="Center" /> TextAlignment="Center" />
</ToggleButton> </ToggleButton>
</StackPanel> </StackPanel>
@@ -94,7 +91,7 @@
TextAlignment="Center" /> TextAlignment="Center" />
<ToggleButton Name="ButtonL"> <ToggleButton Name="ButtonL">
<TextBlock <TextBlock
Text="{Binding Config.ButtonL, Converter={StaticResource Key}}" Text="{Binding Config.ButtonL, Converter={x:Static helpers:KeyValueConverter.Instance}}"
TextAlignment="Center" /> TextAlignment="Center" />
</ToggleButton> </ToggleButton>
</StackPanel> </StackPanel>
@@ -110,7 +107,7 @@
TextAlignment="Center" /> TextAlignment="Center" />
<ToggleButton Name="ButtonMinus"> <ToggleButton Name="ButtonMinus">
<TextBlock <TextBlock
Text="{Binding Config.ButtonMinus, Converter={StaticResource Key}}" Text="{Binding Config.ButtonMinus, Converter={x:Static helpers:KeyValueConverter.Instance}}"
TextAlignment="Center" /> TextAlignment="Center" />
</ToggleButton> </ToggleButton>
</StackPanel> </StackPanel>
@@ -144,7 +141,7 @@
TextAlignment="Center" /> TextAlignment="Center" />
<ToggleButton Name="LeftStickButton"> <ToggleButton Name="LeftStickButton">
<TextBlock <TextBlock
Text="{Binding Config.LeftStickButton, Converter={StaticResource Key}}" Text="{Binding Config.LeftStickButton, Converter={x:Static helpers:KeyValueConverter.Instance}}"
TextAlignment="Center" /> TextAlignment="Center" />
</ToggleButton> </ToggleButton>
</StackPanel> </StackPanel>
@@ -161,7 +158,7 @@
TextAlignment="Center" /> TextAlignment="Center" />
<ToggleButton Name="LeftJoystick" Tag="stick"> <ToggleButton Name="LeftJoystick" Tag="stick">
<TextBlock <TextBlock
Text="{Binding Config.LeftJoystick, Converter={StaticResource Key}}" Text="{Binding Config.LeftJoystick, Converter={x:Static helpers:KeyValueConverter.Instance}}"
TextAlignment="Center" /> TextAlignment="Center" />
</ToggleButton> </ToggleButton>
</StackPanel> </StackPanel>
@@ -254,7 +251,7 @@
TextAlignment="Center" /> TextAlignment="Center" />
<ToggleButton Name="DpadUp"> <ToggleButton Name="DpadUp">
<TextBlock <TextBlock
Text="{Binding Config.DpadUp, Converter={StaticResource Key}}" Text="{Binding Config.DpadUp, Converter={x:Static helpers:KeyValueConverter.Instance}}"
TextAlignment="Center" /> TextAlignment="Center" />
</ToggleButton> </ToggleButton>
</StackPanel> </StackPanel>
@@ -271,7 +268,7 @@
TextAlignment="Center" /> TextAlignment="Center" />
<ToggleButton Name="DpadDown"> <ToggleButton Name="DpadDown">
<TextBlock <TextBlock
Text="{Binding Config.DpadDown, Converter={StaticResource Key}}" Text="{Binding Config.DpadDown, Converter={x:Static helpers:KeyValueConverter.Instance}}"
TextAlignment="Center" /> TextAlignment="Center" />
</ToggleButton> </ToggleButton>
</StackPanel> </StackPanel>
@@ -288,7 +285,7 @@
TextAlignment="Center" /> TextAlignment="Center" />
<ToggleButton Name="DpadLeft"> <ToggleButton Name="DpadLeft">
<TextBlock <TextBlock
Text="{Binding Config.DpadLeft, Converter={StaticResource Key}}" Text="{Binding Config.DpadLeft, Converter={x:Static helpers:KeyValueConverter.Instance}}"
TextAlignment="Center" /> TextAlignment="Center" />
</ToggleButton> </ToggleButton>
</StackPanel> </StackPanel>
@@ -305,7 +302,7 @@
TextAlignment="Center" /> TextAlignment="Center" />
<ToggleButton Name="DpadRight"> <ToggleButton Name="DpadRight">
<TextBlock <TextBlock
Text="{Binding Config.DpadRight, Converter={StaticResource Key}}" Text="{Binding Config.DpadRight, Converter={x:Static helpers:KeyValueConverter.Instance}}"
TextAlignment="Center" /> TextAlignment="Center" />
</ToggleButton> </ToggleButton>
</StackPanel> </StackPanel>
@@ -368,7 +365,7 @@
TextAlignment="Center" /> TextAlignment="Center" />
<ToggleButton Name="LeftButtonSr"> <ToggleButton Name="LeftButtonSr">
<TextBlock <TextBlock
Text="{Binding Config.LeftButtonSr, Converter={StaticResource Key}}" Text="{Binding Config.LeftButtonSr, Converter={x:Static helpers:KeyValueConverter.Instance}}"
TextAlignment="Center" /> TextAlignment="Center" />
</ToggleButton> </ToggleButton>
</StackPanel> </StackPanel>
@@ -386,7 +383,7 @@
TextAlignment="Center" /> TextAlignment="Center" />
<ToggleButton Name="LeftButtonSl"> <ToggleButton Name="LeftButtonSl">
<TextBlock <TextBlock
Text="{Binding Config.LeftButtonSl, Converter={StaticResource Key}}" Text="{Binding Config.LeftButtonSl, Converter={x:Static helpers:KeyValueConverter.Instance}}"
TextAlignment="Center" /> TextAlignment="Center" />
</ToggleButton> </ToggleButton>
</StackPanel> </StackPanel>
@@ -404,7 +401,7 @@
TextAlignment="Center" /> TextAlignment="Center" />
<ToggleButton Name="RightButtonSr"> <ToggleButton Name="RightButtonSr">
<TextBlock <TextBlock
Text="{Binding Config.RightButtonSr, Converter={StaticResource Key}}" Text="{Binding Config.RightButtonSr, Converter={x:Static helpers:KeyValueConverter.Instance}}"
TextAlignment="Center" /> TextAlignment="Center" />
</ToggleButton> </ToggleButton>
</StackPanel> </StackPanel>
@@ -422,7 +419,7 @@
TextAlignment="Center" /> TextAlignment="Center" />
<ToggleButton Name="RightButtonSl"> <ToggleButton Name="RightButtonSl">
<TextBlock <TextBlock
Text="{Binding Config.RightButtonSl, Converter={StaticResource Key}}" Text="{Binding Config.RightButtonSl, Converter={x:Static helpers:KeyValueConverter.Instance}}"
TextAlignment="Center" /> TextAlignment="Center" />
</ToggleButton> </ToggleButton>
</StackPanel> </StackPanel>
@@ -550,7 +547,7 @@
TextAlignment="Center" /> TextAlignment="Center" />
<ToggleButton Name="ButtonZr"> <ToggleButton Name="ButtonZr">
<TextBlock <TextBlock
Text="{Binding Config.ButtonZr, Converter={StaticResource Key}}" Text="{Binding Config.ButtonZr, Converter={x:Static helpers:KeyValueConverter.Instance}}"
TextAlignment="Center" /> TextAlignment="Center" />
</ToggleButton> </ToggleButton>
</StackPanel> </StackPanel>
@@ -568,7 +565,7 @@
TextAlignment="Center" /> TextAlignment="Center" />
<ToggleButton Name="ButtonR"> <ToggleButton Name="ButtonR">
<TextBlock <TextBlock
Text="{Binding Config.ButtonR, Converter={StaticResource Key}}" Text="{Binding Config.ButtonR, Converter={x:Static helpers:KeyValueConverter.Instance}}"
TextAlignment="Center" /> TextAlignment="Center" />
</ToggleButton> </ToggleButton>
</StackPanel> </StackPanel>
@@ -586,7 +583,7 @@
TextAlignment="Center" /> TextAlignment="Center" />
<ToggleButton Name="ButtonPlus"> <ToggleButton Name="ButtonPlus">
<TextBlock <TextBlock
Text="{Binding Config.ButtonPlus, Converter={StaticResource Key}}" Text="{Binding Config.ButtonPlus, Converter={x:Static helpers:KeyValueConverter.Instance}}"
TextAlignment="Center" /> TextAlignment="Center" />
</ToggleButton> </ToggleButton>
</StackPanel> </StackPanel>
@@ -621,7 +618,7 @@
TextAlignment="Center" /> TextAlignment="Center" />
<ToggleButton Name="ButtonA"> <ToggleButton Name="ButtonA">
<TextBlock <TextBlock
Text="{Binding Config.ButtonA, Converter={StaticResource Key}}" Text="{Binding Config.ButtonA, Converter={x:Static helpers:KeyValueConverter.Instance}}"
TextAlignment="Center" /> TextAlignment="Center" />
</ToggleButton> </ToggleButton>
</StackPanel> </StackPanel>
@@ -638,7 +635,7 @@
TextAlignment="Center" /> TextAlignment="Center" />
<ToggleButton Name="ButtonB"> <ToggleButton Name="ButtonB">
<TextBlock <TextBlock
Text="{Binding Config.ButtonB, Converter={StaticResource Key}}" Text="{Binding Config.ButtonB, Converter={x:Static helpers:KeyValueConverter.Instance}}"
TextAlignment="Center" /> TextAlignment="Center" />
</ToggleButton> </ToggleButton>
</StackPanel> </StackPanel>
@@ -655,7 +652,7 @@
TextAlignment="Center" /> TextAlignment="Center" />
<ToggleButton Name="ButtonX"> <ToggleButton Name="ButtonX">
<TextBlock <TextBlock
Text="{Binding Config.ButtonX, Converter={StaticResource Key}}" Text="{Binding Config.ButtonX, Converter={x:Static helpers:KeyValueConverter.Instance}}"
TextAlignment="Center" /> TextAlignment="Center" />
</ToggleButton> </ToggleButton>
</StackPanel> </StackPanel>
@@ -672,7 +669,7 @@
TextAlignment="Center" /> TextAlignment="Center" />
<ToggleButton Name="ButtonY"> <ToggleButton Name="ButtonY">
<TextBlock <TextBlock
Text="{Binding Config.ButtonY, Converter={StaticResource Key}}" Text="{Binding Config.ButtonY, Converter={x:Static helpers:KeyValueConverter.Instance}}"
TextAlignment="Center" /> TextAlignment="Center" />
</ToggleButton> </ToggleButton>
</StackPanel> </StackPanel>
@@ -706,7 +703,7 @@
TextAlignment="Center" /> TextAlignment="Center" />
<ToggleButton Name="RightStickButton"> <ToggleButton Name="RightStickButton">
<TextBlock <TextBlock
Text="{Binding Config.RightStickButton, Converter={StaticResource Key}}" Text="{Binding Config.RightStickButton, Converter={x:Static helpers:KeyValueConverter.Instance}}"
TextAlignment="Center" /> TextAlignment="Center" />
</ToggleButton> </ToggleButton>
</StackPanel> </StackPanel>
@@ -724,7 +721,7 @@
TextAlignment="Center" /> TextAlignment="Center" />
<ToggleButton Name="RightJoystick" Tag="stick"> <ToggleButton Name="RightJoystick" Tag="stick">
<TextBlock <TextBlock
Text="{Binding Config.RightJoystick, Converter={StaticResource Key}}" Text="{Binding Config.RightJoystick, Converter={x:Static helpers:KeyValueConverter.Instance}}"
TextAlignment="Center" /> TextAlignment="Center" />
</ToggleButton> </ToggleButton>
</StackPanel> </StackPanel>
@@ -18,9 +18,6 @@
<Design.DataContext> <Design.DataContext>
<viewModels:KeyboardInputViewModel /> <viewModels:KeyboardInputViewModel />
</Design.DataContext> </Design.DataContext>
<UserControl.Resources>
<helpers:KeyValueConverter x:Key="Key" />
</UserControl.Resources>
<UserControl.Styles> <UserControl.Styles>
<Style Selector="ToggleButton"> <Style Selector="ToggleButton">
<Setter Property="Width" Value="90" /> <Setter Property="Width" Value="90" />
@@ -76,7 +73,7 @@
TextAlignment="Center" /> TextAlignment="Center" />
<ToggleButton Name="ButtonZl"> <ToggleButton Name="ButtonZl">
<TextBlock <TextBlock
Text="{Binding Config.ButtonZl, Converter={StaticResource Key}}" Text="{Binding Config.ButtonZl, Converter={x:Static helpers:KeyValueConverter.Instance}}"
TextAlignment="Center" /> TextAlignment="Center" />
</ToggleButton> </ToggleButton>
</StackPanel> </StackPanel>
@@ -92,7 +89,7 @@
TextAlignment="Center" /> TextAlignment="Center" />
<ToggleButton Name="ButtonL"> <ToggleButton Name="ButtonL">
<TextBlock <TextBlock
Text="{Binding Config.ButtonL, Converter={StaticResource Key}}" Text="{Binding Config.ButtonL, Converter={x:Static helpers:KeyValueConverter.Instance}}"
TextAlignment="Center" /> TextAlignment="Center" />
</ToggleButton> </ToggleButton>
</StackPanel> </StackPanel>
@@ -108,7 +105,7 @@
TextAlignment="Center" /> TextAlignment="Center" />
<ToggleButton Name="ButtonMinus"> <ToggleButton Name="ButtonMinus">
<TextBlock <TextBlock
Text="{Binding Config.ButtonMinus, Converter={StaticResource Key}}" Text="{Binding Config.ButtonMinus, Converter={x:Static helpers:KeyValueConverter.Instance}}"
TextAlignment="Center" /> TextAlignment="Center" />
</ToggleButton> </ToggleButton>
</StackPanel> </StackPanel>
@@ -143,7 +140,7 @@
TextAlignment="Center" /> TextAlignment="Center" />
<ToggleButton Name="LeftStickButton"> <ToggleButton Name="LeftStickButton">
<TextBlock <TextBlock
Text="{Binding Config.LeftStickButton, Converter={StaticResource Key}}" Text="{Binding Config.LeftStickButton, Converter={x:Static helpers:KeyValueConverter.Instance}}"
TextAlignment="Center" /> TextAlignment="Center" />
</ToggleButton> </ToggleButton>
</StackPanel> </StackPanel>
@@ -160,7 +157,7 @@
TextAlignment="Center" /> TextAlignment="Center" />
<ToggleButton Name="LeftStickUp"> <ToggleButton Name="LeftStickUp">
<TextBlock <TextBlock
Text="{Binding Config.LeftStickUp, Converter={StaticResource Key}}" Text="{Binding Config.LeftStickUp, Converter={x:Static helpers:KeyValueConverter.Instance}}"
TextAlignment="Center" /> TextAlignment="Center" />
</ToggleButton> </ToggleButton>
</StackPanel> </StackPanel>
@@ -177,7 +174,7 @@
TextAlignment="Center" /> TextAlignment="Center" />
<ToggleButton Name="LeftStickDown"> <ToggleButton Name="LeftStickDown">
<TextBlock <TextBlock
Text="{Binding Config.LeftStickDown, Converter={StaticResource Key}}" Text="{Binding Config.LeftStickDown, Converter={x:Static helpers:KeyValueConverter.Instance}}"
TextAlignment="Center" /> TextAlignment="Center" />
</ToggleButton> </ToggleButton>
</StackPanel> </StackPanel>
@@ -194,7 +191,7 @@
TextAlignment="Center" /> TextAlignment="Center" />
<ToggleButton Name="LeftStickLeft"> <ToggleButton Name="LeftStickLeft">
<TextBlock <TextBlock
Text="{Binding Config.LeftStickLeft, Converter={StaticResource Key}}" Text="{Binding Config.LeftStickLeft, Converter={x:Static helpers:KeyValueConverter.Instance}}"
TextAlignment="Center" /> TextAlignment="Center" />
</ToggleButton> </ToggleButton>
</StackPanel> </StackPanel>
@@ -211,7 +208,7 @@
TextAlignment="Center" /> TextAlignment="Center" />
<ToggleButton Name="LeftStickRight"> <ToggleButton Name="LeftStickRight">
<TextBlock <TextBlock
Text="{Binding Config.LeftStickRight, Converter={StaticResource Key}}" Text="{Binding Config.LeftStickRight, Converter={x:Static helpers:KeyValueConverter.Instance}}"
TextAlignment="Center" /> TextAlignment="Center" />
</ToggleButton> </ToggleButton>
</StackPanel> </StackPanel>
@@ -247,7 +244,7 @@
TextAlignment="Center" /> TextAlignment="Center" />
<ToggleButton Name="DpadUp"> <ToggleButton Name="DpadUp">
<TextBlock <TextBlock
Text="{Binding Config.DpadUp, Converter={StaticResource Key}}" Text="{Binding Config.DpadUp, Converter={x:Static helpers:KeyValueConverter.Instance}}"
TextAlignment="Center" /> TextAlignment="Center" />
</ToggleButton> </ToggleButton>
</StackPanel> </StackPanel>
@@ -264,7 +261,7 @@
TextAlignment="Center" /> TextAlignment="Center" />
<ToggleButton Name="DpadDown"> <ToggleButton Name="DpadDown">
<TextBlock <TextBlock
Text="{Binding Config.DpadDown, Converter={StaticResource Key}}" Text="{Binding Config.DpadDown, Converter={x:Static helpers:KeyValueConverter.Instance}}"
TextAlignment="Center" /> TextAlignment="Center" />
</ToggleButton> </ToggleButton>
</StackPanel> </StackPanel>
@@ -281,7 +278,7 @@
TextAlignment="Center" /> TextAlignment="Center" />
<ToggleButton Name="DpadLeft"> <ToggleButton Name="DpadLeft">
<TextBlock <TextBlock
Text="{Binding Config.DpadLeft, Converter={StaticResource Key}}" Text="{Binding Config.DpadLeft, Converter={x:Static helpers:KeyValueConverter.Instance}}"
TextAlignment="Center" /> TextAlignment="Center" />
</ToggleButton> </ToggleButton>
</StackPanel> </StackPanel>
@@ -298,7 +295,7 @@
TextAlignment="Center" /> TextAlignment="Center" />
<ToggleButton Name="DpadRight"> <ToggleButton Name="DpadRight">
<TextBlock <TextBlock
Text="{Binding Config.DpadRight, Converter={StaticResource Key}}" Text="{Binding Config.DpadRight, Converter={x:Static helpers:KeyValueConverter.Instance}}"
TextAlignment="Center" /> TextAlignment="Center" />
</ToggleButton> </ToggleButton>
</StackPanel> </StackPanel>
@@ -341,7 +338,7 @@
TextAlignment="Center" /> TextAlignment="Center" />
<ToggleButton Name="LeftButtonSr"> <ToggleButton Name="LeftButtonSr">
<TextBlock <TextBlock
Text="{Binding Config.LeftButtonSr, Converter={StaticResource Key}}" Text="{Binding Config.LeftButtonSr, Converter={x:Static helpers:KeyValueConverter.Instance}}"
TextAlignment="Center" /> TextAlignment="Center" />
</ToggleButton> </ToggleButton>
</StackPanel> </StackPanel>
@@ -359,7 +356,7 @@
TextAlignment="Center" /> TextAlignment="Center" />
<ToggleButton Name="LeftButtonSl"> <ToggleButton Name="LeftButtonSl">
<TextBlock <TextBlock
Text="{Binding Config.LeftButtonSl, Converter={StaticResource Key}}" Text="{Binding Config.LeftButtonSl, Converter={x:Static helpers:KeyValueConverter.Instance}}"
TextAlignment="Center" /> TextAlignment="Center" />
</ToggleButton> </ToggleButton>
</StackPanel> </StackPanel>
@@ -377,7 +374,7 @@
TextAlignment="Center" /> TextAlignment="Center" />
<ToggleButton Name="RightButtonSr"> <ToggleButton Name="RightButtonSr">
<TextBlock <TextBlock
Text="{Binding Config.RightButtonSr, Converter={StaticResource Key}}" Text="{Binding Config.RightButtonSr, Converter={x:Static helpers:KeyValueConverter.Instance}}"
TextAlignment="Center" /> TextAlignment="Center" />
</ToggleButton> </ToggleButton>
</StackPanel> </StackPanel>
@@ -395,7 +392,7 @@
TextAlignment="Center" /> TextAlignment="Center" />
<ToggleButton Name="RightButtonSl"> <ToggleButton Name="RightButtonSl">
<TextBlock <TextBlock
Text="{Binding Config.RightButtonSl, Converter={StaticResource Key}}" Text="{Binding Config.RightButtonSl, Converter={x:Static helpers:KeyValueConverter.Instance}}"
TextAlignment="Center" /> TextAlignment="Center" />
</ToggleButton> </ToggleButton>
</StackPanel> </StackPanel>
@@ -437,7 +434,7 @@
TextAlignment="Center" /> TextAlignment="Center" />
<ToggleButton Name="ButtonZr"> <ToggleButton Name="ButtonZr">
<TextBlock <TextBlock
Text="{Binding Config.ButtonZr, Converter={StaticResource Key}}" Text="{Binding Config.ButtonZr, Converter={x:Static helpers:KeyValueConverter.Instance}}"
TextAlignment="Center" /> TextAlignment="Center" />
</ToggleButton> </ToggleButton>
</StackPanel> </StackPanel>
@@ -455,7 +452,7 @@
TextAlignment="Center" /> TextAlignment="Center" />
<ToggleButton Name="ButtonR"> <ToggleButton Name="ButtonR">
<TextBlock <TextBlock
Text="{Binding Config.ButtonR, Converter={StaticResource Key}}" Text="{Binding Config.ButtonR, Converter={x:Static helpers:KeyValueConverter.Instance}}"
TextAlignment="Center" /> TextAlignment="Center" />
</ToggleButton> </ToggleButton>
</StackPanel> </StackPanel>
@@ -473,7 +470,7 @@
TextAlignment="Center" /> TextAlignment="Center" />
<ToggleButton Name="ButtonPlus"> <ToggleButton Name="ButtonPlus">
<TextBlock <TextBlock
Text="{Binding Config.ButtonPlus, Converter={StaticResource Key}}" Text="{Binding Config.ButtonPlus, Converter={x:Static helpers:KeyValueConverter.Instance}}"
TextAlignment="Center" /> TextAlignment="Center" />
</ToggleButton> </ToggleButton>
</StackPanel> </StackPanel>
@@ -508,7 +505,7 @@
TextAlignment="Center" /> TextAlignment="Center" />
<ToggleButton Name="ButtonA"> <ToggleButton Name="ButtonA">
<TextBlock <TextBlock
Text="{Binding Config.ButtonA, Converter={StaticResource Key}}" Text="{Binding Config.ButtonA, Converter={x:Static helpers:KeyValueConverter.Instance}}"
TextAlignment="Center" /> TextAlignment="Center" />
</ToggleButton> </ToggleButton>
</StackPanel> </StackPanel>
@@ -525,7 +522,7 @@
TextAlignment="Center" /> TextAlignment="Center" />
<ToggleButton Name="ButtonB"> <ToggleButton Name="ButtonB">
<TextBlock <TextBlock
Text="{Binding Config.ButtonB, Converter={StaticResource Key}}" Text="{Binding Config.ButtonB, Converter={x:Static helpers:KeyValueConverter.Instance}}"
TextAlignment="Center" /> TextAlignment="Center" />
</ToggleButton> </ToggleButton>
</StackPanel> </StackPanel>
@@ -542,7 +539,7 @@
TextAlignment="Center" /> TextAlignment="Center" />
<ToggleButton Name="ButtonX"> <ToggleButton Name="ButtonX">
<TextBlock <TextBlock
Text="{Binding Config.ButtonX, Converter={StaticResource Key}}" Text="{Binding Config.ButtonX, Converter={x:Static helpers:KeyValueConverter.Instance}}"
TextAlignment="Center" /> TextAlignment="Center" />
</ToggleButton> </ToggleButton>
</StackPanel> </StackPanel>
@@ -559,7 +556,7 @@
TextAlignment="Center" /> TextAlignment="Center" />
<ToggleButton Name="ButtonY"> <ToggleButton Name="ButtonY">
<TextBlock <TextBlock
Text="{Binding Config.ButtonY, Converter={StaticResource Key}}" Text="{Binding Config.ButtonY, Converter={x:Static helpers:KeyValueConverter.Instance}}"
TextAlignment="Center" /> TextAlignment="Center" />
</ToggleButton> </ToggleButton>
</StackPanel> </StackPanel>
@@ -594,7 +591,7 @@
TextAlignment="Center" /> TextAlignment="Center" />
<ToggleButton Name="RightStickButton"> <ToggleButton Name="RightStickButton">
<TextBlock <TextBlock
Text="{Binding Config.RightStickButton, Converter={StaticResource Key}}" Text="{Binding Config.RightStickButton, Converter={x:Static helpers:KeyValueConverter.Instance}}"
TextAlignment="Center" /> TextAlignment="Center" />
</ToggleButton> </ToggleButton>
</StackPanel> </StackPanel>
@@ -611,7 +608,7 @@
TextAlignment="Center" /> TextAlignment="Center" />
<ToggleButton Name="RightStickUp"> <ToggleButton Name="RightStickUp">
<TextBlock <TextBlock
Text="{Binding Config.RightStickUp, Converter={StaticResource Key}}" Text="{Binding Config.RightStickUp, Converter={x:Static helpers:KeyValueConverter.Instance}}"
TextAlignment="Center" /> TextAlignment="Center" />
</ToggleButton> </ToggleButton>
</StackPanel> </StackPanel>
@@ -628,7 +625,7 @@
TextAlignment="Center" /> TextAlignment="Center" />
<ToggleButton Name="RightStickDown"> <ToggleButton Name="RightStickDown">
<TextBlock <TextBlock
Text="{Binding Config.RightStickDown, Converter={StaticResource Key}}" Text="{Binding Config.RightStickDown, Converter={x:Static helpers:KeyValueConverter.Instance}}"
TextAlignment="Center" /> TextAlignment="Center" />
</ToggleButton> </ToggleButton>
</StackPanel> </StackPanel>
@@ -645,7 +642,7 @@
TextAlignment="Center" /> TextAlignment="Center" />
<ToggleButton Name="RightStickLeft"> <ToggleButton Name="RightStickLeft">
<TextBlock <TextBlock
Text="{Binding Config.RightStickLeft, Converter={StaticResource Key}}" Text="{Binding Config.RightStickLeft, Converter={x:Static helpers:KeyValueConverter.Instance}}"
TextAlignment="Center" /> TextAlignment="Center" />
</ToggleButton> </ToggleButton>
</StackPanel> </StackPanel>
@@ -662,7 +659,7 @@
TextAlignment="Center" /> TextAlignment="Center" />
<ToggleButton Name="RightStickRight"> <ToggleButton Name="RightStickRight">
<TextBlock <TextBlock
Text="{Binding Config.RightStickRight, Converter={StaticResource Key}}" Text="{Binding Config.RightStickRight, Converter={x:Static helpers:KeyValueConverter.Instance}}"
TextAlignment="Center" /> TextAlignment="Center" />
</ToggleButton> </ToggleButton>
</StackPanel> </StackPanel>
+21 -3
View File
@@ -11,7 +11,7 @@
x:Class="Ryujinx.UI.Views.Input.LedInputView"> x:Class="Ryujinx.UI.Views.Input.LedInputView">
<StackPanel Orientation="Vertical" HorizontalAlignment="Center"> <StackPanel Orientation="Vertical" HorizontalAlignment="Center">
<StackPanel Orientation="Horizontal" IsVisible="{Binding ParentModel.CanClearLed}"> <StackPanel Orientation="Horizontal" IsVisible="{Binding ParentModel.CanClearLed}">
<TextBlock MinWidth="75" MaxWidth="150" Text="{ext:Locale ControllerSettingsLedColorDisable}" /> <TextBlock MinWidth="75" MaxWidth="200" Text="{ext:Locale ControllerSettingsLedColorDisable}" />
<CheckBox <CheckBox
Margin="5" Margin="5"
MinWidth="0" MinWidth="0"
@@ -20,15 +20,33 @@
</CheckBox> </CheckBox>
</StackPanel> </StackPanel>
<StackPanel Orientation="Horizontal" IsEnabled="{Binding !TurnOffLed}"> <StackPanel Orientation="Horizontal" IsEnabled="{Binding !TurnOffLed}">
<TextBlock MinWidth="75" MaxWidth="150" Text="{ext:Locale ControllerSettingsLedColorRainbow}" /> <TextBlock MinWidth="75" MaxWidth="200" Text="{ext:Locale ControllerSettingsLedColorRainbow}" />
<CheckBox <CheckBox
Margin="5" Margin="5"
MinWidth="0" MinWidth="0"
IsChecked="{Binding UseRainbowLed, Mode=TwoWay}"> IsChecked="{Binding UseRainbowLed, Mode=TwoWay}">
</CheckBox> </CheckBox>
</StackPanel> </StackPanel>
<StackPanel Orientation="Horizontal" IsEnabled="{Binding !TurnOffLed}">
<TextBlock MinWidth="75" MaxWidth="200" Text="{ext:Locale ControllerSettingsLedColorRainbowSpeed}" />
<Slider HorizontalAlignment="Center"
Value="{Binding RainbowSpeed}"
Width="175"
Margin="0,-3,0,0"
Height="32"
Padding="0,-5"
TickFrequency="0.25"
LargeChange="1"
SmallChange="0.25"
VerticalAlignment="Center"
Minimum="1"
Maximum="10" />
<TextBlock Margin="5,0"
MinWidth="75"
Text="{Binding RainbowSpeedText}" />
</StackPanel>
<StackPanel Orientation="Horizontal" IsEnabled="{Binding ShowLedColorPicker}"> <StackPanel Orientation="Horizontal" IsEnabled="{Binding ShowLedColorPicker}">
<TextBlock MinWidth="75" MaxWidth="150" Text="{ext:Locale ControllerSettingsLedColor}" /> <TextBlock MinWidth="75" MaxWidth="200" Text="{ext:Locale ControllerSettingsLedColor}" />
<ui:ColorPickerButton <ui:ColorPickerButton
Margin="5" Margin="5"
IsMoreButtonVisible="False" IsMoreButtonVisible="False"
@@ -1,11 +1,9 @@
using Avalonia; using Avalonia;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Markup.Xaml;
using FluentAvalonia.UI.Controls; using FluentAvalonia.UI.Controls;
using Ryujinx.Ava.Common.Locale; using Ryujinx.Ava.Common.Locale;
using Ryujinx.Ava.UI.Models.Input; using Ryujinx.Ava.UI.Models.Input;
using Ryujinx.Ava.UI.ViewModels.Input; using Ryujinx.Ava.UI.ViewModels.Input;
using Ryujinx.Ava.UI.Views.Input;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace Ryujinx.UI.Views.Input namespace Ryujinx.UI.Views.Input
@@ -134,8 +134,13 @@ namespace Ryujinx.Ava.UI.Views.Main
{ {
Window.SettingsWindow = new(Window.VirtualFileSystem, Window.ContentManager); Window.SettingsWindow = new(Window.VirtualFileSystem, Window.ContentManager);
Rainbow.Enable();
await Window.SettingsWindow.ShowDialog(Window); await Window.SettingsWindow.ShowDialog(Window);
Rainbow.Disable();
Rainbow.Reset();
Window.SettingsWindow = null; Window.SettingsWindow = null;
ViewModel.LoadConfigurableHotKeys(); ViewModel.LoadConfigurableHotKeys();
@@ -1,4 +1,4 @@
<UserControl <UserControl
x:Class="Ryujinx.Ava.UI.Views.Settings.SettingsHotkeysView" x:Class="Ryujinx.Ava.UI.Views.Settings.SettingsHotkeysView"
xmlns="https://github.com/avaloniaui" xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
@@ -14,21 +14,19 @@
<Design.DataContext> <Design.DataContext>
<viewModels:SettingsViewModel /> <viewModels:SettingsViewModel />
</Design.DataContext> </Design.DataContext>
<UserControl.Resources>
<helpers:KeyValueConverter x:Key="Key" />
</UserControl.Resources>
<UserControl.Styles> <UserControl.Styles>
<Style Selector="StackPanel > StackPanel"> <Style Selector="StackPanel StackPanel">
<Setter Property="Margin" Value="10, 0, 0, 0" /> <Setter Property="Margin" Value="10, 0, 0, 0" />
<Setter Property="Orientation" Value="Horizontal" /> <Setter Property="Orientation" Value="Horizontal" />
</Style> </Style>
<Style Selector="StackPanel > StackPanel > TextBlock"> <Style Selector="StackPanel StackPanel > TextBlock">
<Setter Property="VerticalAlignment" Value="Center" /> <Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="Width" Value="230" /> <Setter Property="Width" Value="230" />
</Style> </Style>
<Style Selector="ToggleButton"> <Style Selector="ToggleButton, Button">
<Setter Property="Width" Value="90" /> <Setter Property="Width" Value="90" />
<Setter Property="Height" Value="27" /> <Setter Property="Height" Value="27" />
<Setter Property="Padding" Value="0,5,0,5" /> <!-- Added vertical padding -->
</Style> </Style>
<Style Selector="ToggleButton > TextBlock"> <Style Selector="ToggleButton > TextBlock">
<Setter Property="TextAlignment" Value="Center" /> <Setter Property="TextAlignment" Value="Center" />
@@ -42,80 +40,124 @@
VerticalScrollBarVisibility="Auto"> VerticalScrollBarVisibility="Auto">
<Border Classes="settings"> <Border Classes="settings">
<StackPanel <StackPanel
Name="SettingButtons"
Margin="10" Margin="10"
HorizontalAlignment="Stretch"
Orientation="Vertical" Orientation="Vertical"
Spacing="10"> Spacing="10"
Name="SettingButtons">
<TextBlock <TextBlock
Classes="h1" Classes="h1"
Text="{ext:Locale SettingsTabHotkeysHotkeys}" /> Text="{ext:Locale SettingsTabHotkeysHotkeys}" />
<StackPanel
Margin="10,0,0,0"
Spacing="10"
Orientation="Vertical">
<StackPanel> <StackPanel>
<TextBlock Text="{ext:Locale SettingsTabHotkeysToggleVSyncModeHotkey}" /> <TextBlock Text="{ext:Locale SettingsTabHotkeysToggleVSyncModeHotkey}" />
<ToggleButton Name="ToggleVSyncMode"> <ToggleButton Name="ToggleVSyncMode">
<TextBlock Text="{Binding KeyboardHotkey.ToggleVSyncMode, Converter={StaticResource Key}}" /> <TextBlock Text="{Binding KeyboardHotkey.ToggleVSyncMode, Converter={x:Static helpers:KeyValueConverter.Instance}}" />
</ToggleButton> </ToggleButton>
</StackPanel> </StackPanel>
<StackPanel> <StackPanel>
<TextBlock Text="{ext:Locale SettingsTabHotkeysScreenshotHotkey}" /> <TextBlock Text="{ext:Locale SettingsTabHotkeysScreenshotHotkey}" />
<ToggleButton Name="Screenshot"> <ToggleButton Name="Screenshot">
<TextBlock Text="{Binding KeyboardHotkey.Screenshot, Converter={StaticResource Key}}" /> <TextBlock Text="{Binding KeyboardHotkey.Screenshot, Converter={x:Static helpers:KeyValueConverter.Instance}}" />
</ToggleButton> </ToggleButton>
</StackPanel> </StackPanel>
<StackPanel> <StackPanel>
<TextBlock Text="{ext:Locale SettingsTabHotkeysShowUiHotkey}" /> <TextBlock Text="{ext:Locale SettingsTabHotkeysShowUiHotkey}" />
<ToggleButton Name="ShowUI"> <ToggleButton Name="ShowUI">
<TextBlock Text="{Binding KeyboardHotkey.ShowUI, Converter={StaticResource Key}}" /> <TextBlock Text="{Binding KeyboardHotkey.ShowUI, Converter={x:Static helpers:KeyValueConverter.Instance}}" />
</ToggleButton> </ToggleButton>
</StackPanel> </StackPanel>
<StackPanel> <StackPanel>
<TextBlock Text="{ext:Locale SettingsTabHotkeysPauseHotkey}" /> <TextBlock Text="{ext:Locale SettingsTabHotkeysPauseHotkey}" />
<ToggleButton Name="Pause"> <ToggleButton Name="Pause">
<TextBlock Text="{Binding KeyboardHotkey.Pause, Converter={StaticResource Key}}" /> <TextBlock Text="{Binding KeyboardHotkey.Pause, Converter={x:Static helpers:KeyValueConverter.Instance}}" />
</ToggleButton> </ToggleButton>
</StackPanel> </StackPanel>
<StackPanel> <StackPanel>
<TextBlock Text="{ext:Locale SettingsTabHotkeysToggleMuteHotkey}" /> <TextBlock Text="{ext:Locale SettingsTabHotkeysToggleMuteHotkey}" />
<ToggleButton Name="ToggleMute"> <ToggleButton Name="ToggleMute">
<TextBlock Text="{Binding KeyboardHotkey.ToggleMute, Converter={StaticResource Key}}" /> <TextBlock Text="{Binding KeyboardHotkey.ToggleMute, Converter={x:Static helpers:KeyValueConverter.Instance}}" />
</ToggleButton> </ToggleButton>
</StackPanel> </StackPanel>
<StackPanel> <StackPanel>
<TextBlock Text="{ext:Locale SettingsTabHotkeysResScaleUpHotkey}" /> <TextBlock Text="{ext:Locale SettingsTabHotkeysResScaleUpHotkey}" />
<ToggleButton Name="ResScaleUp"> <ToggleButton Name="ResScaleUp">
<TextBlock Text="{Binding KeyboardHotkey.ResScaleUp, Converter={StaticResource Key}}" /> <TextBlock Text="{Binding KeyboardHotkey.ResScaleUp, Converter={x:Static helpers:KeyValueConverter.Instance}}" />
</ToggleButton> </ToggleButton>
</StackPanel> </StackPanel>
<StackPanel> <StackPanel>
<TextBlock Text="{ext:Locale SettingsTabHotkeysResScaleDownHotkey}" /> <TextBlock Text="{ext:Locale SettingsTabHotkeysResScaleDownHotkey}" />
<ToggleButton Name="ResScaleDown"> <ToggleButton Name="ResScaleDown">
<TextBlock Text="{Binding KeyboardHotkey.ResScaleDown, Converter={StaticResource Key}}" /> <TextBlock Text="{Binding KeyboardHotkey.ResScaleDown, Converter={x:Static helpers:KeyValueConverter.Instance}}" />
</ToggleButton> </ToggleButton>
</StackPanel> </StackPanel>
<StackPanel> <StackPanel>
<TextBlock Text="{ext:Locale SettingsTabHotkeysVolumeUpHotkey}" /> <TextBlock Text="{ext:Locale SettingsTabHotkeysVolumeUpHotkey}" />
<ToggleButton Name="VolumeUp"> <ToggleButton Name="VolumeUp">
<TextBlock Text="{Binding KeyboardHotkey.VolumeUp, Converter={StaticResource Key}}" /> <TextBlock Text="{Binding KeyboardHotkey.VolumeUp, Converter={x:Static helpers:KeyValueConverter.Instance}}" />
</ToggleButton> </ToggleButton>
</StackPanel> </StackPanel>
<StackPanel> <StackPanel>
<TextBlock Text="{ext:Locale SettingsTabHotkeysVolumeDownHotkey}" /> <TextBlock Text="{ext:Locale SettingsTabHotkeysVolumeDownHotkey}" />
<ToggleButton Name="VolumeDown"> <ToggleButton Name="VolumeDown">
<TextBlock Text="{Binding KeyboardHotkey.VolumeDown, Converter={StaticResource Key}}" /> <TextBlock Text="{Binding KeyboardHotkey.VolumeDown, Converter={x:Static helpers:KeyValueConverter.Instance}}" />
</ToggleButton> </ToggleButton>
</StackPanel> </StackPanel>
<StackPanel Margin="10,0,0,0" Orientation="Horizontal"> <StackPanel Margin="10,0,0,0" Orientation="Horizontal">
<TextBlock Text="{ext:Locale SettingsTabHotkeysIncrementCustomVSyncIntervalHotkey}" /> <TextBlock Text="{ext:Locale SettingsTabHotkeysIncrementCustomVSyncIntervalHotkey}" />
<ToggleButton Name="CustomVSyncIntervalIncrement"> <ToggleButton Name="CustomVSyncIntervalIncrement">
<TextBlock Text="{Binding KeyboardHotkey.CustomVSyncIntervalIncrement, Converter={StaticResource Key}}" /> <TextBlock Text="{Binding KeyboardHotkey.CustomVSyncIntervalIncrement, Converter={x:Static helpers:KeyValueConverter.Instance}}" />
</ToggleButton> </ToggleButton>
</StackPanel> </StackPanel>
<StackPanel Margin="10,0,0,0" Orientation="Horizontal"> <StackPanel Margin="10,0,0,0" Orientation="Horizontal">
<TextBlock Text="{ext:Locale SettingsTabHotkeysDecrementCustomVSyncIntervalHotkey}" /> <TextBlock Text="{ext:Locale SettingsTabHotkeysDecrementCustomVSyncIntervalHotkey}" />
<ToggleButton Name="CustomVSyncIntervalDecrement"> <ToggleButton Name="CustomVSyncIntervalDecrement">
<TextBlock Text="{Binding KeyboardHotkey.CustomVSyncIntervalDecrement, Converter={StaticResource Key}}" /> <TextBlock Text="{Binding KeyboardHotkey.CustomVSyncIntervalDecrement, Converter={x:Static helpers:KeyValueConverter.Instance}}" />
</ToggleButton> </ToggleButton>
</StackPanel> </StackPanel>
</StackPanel> </StackPanel>
<Separator Height="1" />
<StackPanel Margin="0">
<TextBlock
Classes="h1"
Text="{ext:Locale SettingsTabHotkeysCycleControllers}" />
<StackPanel Orientation="Horizontal" Spacing="10">
<Button
Content="{ext:Locale SettingsTabGeneralAdd}"
Margin="10,0,0,0"
Command="{Binding KeyboardHotkey.AddCycleController}" />
<Button
Content="{ext:Locale SettingsTabGeneralRemove}"
IsEnabled="{Binding KeyboardHotkey.CanRemoveCycleController}"
Command="{Binding KeyboardHotkey.RemoveCycleController}" />
</StackPanel>
</StackPanel>
<ItemsControl ItemsSource="{Binding KeyboardHotkey.CycleControllers}"
Name="CycleControllers">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel
Margin="10,0,0,0"
Orientation="Vertical"
Spacing="10" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Player}" />
<ToggleButton>
<TextBlock
Text="{Binding Hotkey, Converter={x:Static helpers:KeyValueConverter.Instance}}" />
</ToggleButton>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</Border> </Border>
</ScrollViewer> </ScrollViewer>
</UserControl> </UserControl>
@@ -3,11 +3,14 @@ using Avalonia.Controls.Primitives;
using Avalonia.Input; using Avalonia.Input;
using Avalonia.Interactivity; using Avalonia.Interactivity;
using Avalonia.LogicalTree; using Avalonia.LogicalTree;
using Avalonia.VisualTree;
using DynamicData;
using Ryujinx.Ava.Input; using Ryujinx.Ava.Input;
using Ryujinx.Ava.UI.Helpers; using Ryujinx.Ava.UI.Helpers;
using Ryujinx.Ava.UI.ViewModels; using Ryujinx.Ava.UI.ViewModels;
using Ryujinx.Input; using Ryujinx.Input;
using Ryujinx.Input.Assigner; using Ryujinx.Input.Assigner;
using System.Linq;
using Button = Ryujinx.Input.Button; using Button = Ryujinx.Input.Button;
using Key = Ryujinx.Common.Configuration.Hid.Key; using Key = Ryujinx.Common.Configuration.Hid.Key;
@@ -21,16 +24,21 @@ namespace Ryujinx.Ava.UI.Views.Settings
public SettingsHotkeysView() public SettingsHotkeysView()
{ {
InitializeComponent(); InitializeComponent();
RegisterEvents();
_avaloniaKeyboardDriver = new AvaloniaKeyboardDriver(this);
CycleControllers.LayoutUpdated += (_, _1) => RegisterEvents();
}
private void RegisterEvents()
{
foreach (ILogical visual in SettingButtons.GetLogicalDescendants()) foreach (ILogical visual in SettingButtons.GetLogicalDescendants())
{ {
if (visual is ToggleButton button and not CheckBox) if (visual is ToggleButton button and not CheckBox)
{ {
button.IsCheckedChanged -= Button_IsCheckedChanged;
button.IsCheckedChanged += Button_IsCheckedChanged; button.IsCheckedChanged += Button_IsCheckedChanged;
} }
} }
_avaloniaKeyboardDriver = new AvaloniaKeyboardDriver(this);
} }
protected override void OnPointerReleased(PointerReleasedEventArgs e) protected override void OnPointerReleased(PointerReleasedEventArgs e)
@@ -116,6 +124,13 @@ namespace Ryujinx.Ava.UI.Views.Settings
case "CustomVSyncIntervalDecrement": case "CustomVSyncIntervalDecrement":
viewModel.KeyboardHotkey.CustomVSyncIntervalDecrement = buttonValue.AsHidType<Key>(); viewModel.KeyboardHotkey.CustomVSyncIntervalDecrement = buttonValue.AsHidType<Key>();
break; break;
default:
var index = button.FindAncestorOfType<ItemsControl>().GetLogicalDescendants().OfType<ToggleButton>().IndexOf(button);
if (index >= 0 && viewModel.KeyboardHotkey.CycleControllers != null)
{
viewModel.KeyboardHotkey.CycleControllers[index].Hotkey = buttonValue.AsHidType<Key>();
}
break;
} }
} }
}; };
@@ -7,23 +7,26 @@ namespace Ryujinx.Ava.UI.Views.Settings
{ {
public partial class SettingsNetworkView : UserControl public partial class SettingsNetworkView : UserControl
{ {
private readonly Random _random;
public SettingsViewModel ViewModel; public SettingsViewModel ViewModel;
public SettingsNetworkView() public SettingsNetworkView()
{ {
_random = new Random();
InitializeComponent(); InitializeComponent();
} }
private void GenLdnPassButton_OnClick(object sender, RoutedEventArgs e) private void GenLdnPassButton_OnClick(object sender, RoutedEventArgs e)
{ {
byte[] code = new byte[4]; byte[] code = new byte[4];
new Random().NextBytes(code); _random.NextBytes(code);
ViewModel.LdnPassphrase = $"Ryujinx-{BitConverter.ToUInt32(code):x8}"; ViewModel.LdnPassphrase = $"Ryujinx-{BitConverter.ToUInt32(code):x8}";
} }
private void ClearLdnPassButton_OnClick(object sender, RoutedEventArgs e) private void ClearLdnPassButton_OnClick(object sender, RoutedEventArgs e)
{ {
ViewModel.LdnPassphrase = ""; ViewModel.LdnPassphrase = string.Empty;
} }
} }
} }
@@ -10,9 +10,6 @@
xmlns:helpers="clr-namespace:Ryujinx.Ava.UI.Helpers" xmlns:helpers="clr-namespace:Ryujinx.Ava.UI.Helpers"
mc:Ignorable="d" mc:Ignorable="d"
x:DataType="viewModels:SettingsViewModel"> x:DataType="viewModels:SettingsViewModel">
<UserControl.Resources>
<helpers:TimeZoneConverter x:Key="TimeZone" />
</UserControl.Resources>
<Design.DataContext> <Design.DataContext>
<viewModels:SettingsViewModel /> <viewModels:SettingsViewModel />
</Design.DataContext> </Design.DataContext>
@@ -162,7 +159,7 @@
Text="{Binding Path=TimeZone, Mode=OneWay}" Text="{Binding Path=TimeZone, Mode=OneWay}"
TextChanged="TimeZoneBox_OnTextChanged" TextChanged="TimeZoneBox_OnTextChanged"
ToolTip.Tip="{ext:Locale TimezoneTooltip}" ToolTip.Tip="{ext:Locale TimezoneTooltip}"
ValueMemberBinding="{Binding Mode=OneWay, Converter={StaticResource TimeZone}}" /> ValueMemberBinding="{Binding Mode=OneWay, Converter={x:Static helpers:TimeZoneConverter.Instance}}" />
</StackPanel> </StackPanel>
<StackPanel <StackPanel
Margin="0,0,0,10" Margin="0,0,0,10"
@@ -14,9 +14,6 @@
mc:Ignorable="d" mc:Ignorable="d"
Focusable="True" Focusable="True"
x:DataType="models:TempProfile"> x:DataType="models:TempProfile">
<UserControl.Resources>
<helpers:BitmapArrayValueConverter x:Key="ByteImage" />
</UserControl.Resources>
<Grid Margin="0"> <Grid Margin="0">
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" />
@@ -74,7 +71,7 @@
Margin="0" Margin="0"
HorizontalAlignment="Stretch" HorizontalAlignment="Stretch"
VerticalAlignment="Top" VerticalAlignment="Top"
Source="{Binding Image, Converter={StaticResource ByteImage}}" /> Source="{Binding Image, Converter={x:Static helpers:BitmapArrayValueConverter.Instance}}" />
</Panel> </Panel>
</Border> </Border>
</StackPanel> </StackPanel>
@@ -17,9 +17,6 @@
<Design.DataContext> <Design.DataContext>
<viewModels:UserFirmwareAvatarSelectorViewModel /> <viewModels:UserFirmwareAvatarSelectorViewModel />
</Design.DataContext> </Design.DataContext>
<UserControl.Resources>
<helpers:BitmapArrayValueConverter x:Key="ByteImage" />
</UserControl.Resources>
<Grid <Grid
Margin="0" Margin="0"
HorizontalAlignment="Stretch" HorizontalAlignment="Stretch"
@@ -62,7 +59,7 @@
<Panel <Panel
Background="{Binding BackgroundColor}" Background="{Binding BackgroundColor}"
Margin="5"> Margin="5">
<Image Source="{Binding Data, Converter={StaticResource ByteImage}}" /> <Image Source="{Binding Data, Converter={x:Static helpers:BitmapArrayValueConverter.Instance}}" />
</Panel> </Panel>
</DataTemplate> </DataTemplate>
</ListBox.ItemTemplate> </ListBox.ItemTemplate>
@@ -19,9 +19,6 @@
<Design.DataContext> <Design.DataContext>
<viewModels:UserSaveManagerViewModel /> <viewModels:UserSaveManagerViewModel />
</Design.DataContext> </Design.DataContext>
<UserControl.Resources>
<helpers:BitmapArrayValueConverter x:Key="ByteImage" />
</UserControl.Resources>
<Grid> <Grid>
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
@@ -147,7 +144,7 @@
IsVisible="{Binding InGameList}" IsVisible="{Binding InGameList}"
Width="42" Width="42"
Height="42" Height="42"
Source="{Binding Icon, Converter={StaticResource ByteImage}}" /> Source="{Binding Icon, Converter={x:Static helpers:BitmapArrayValueConverter.Instance}}" />
<TextBlock <TextBlock
MaxLines="3" MaxLines="3"
Width="320" Width="320"
@@ -15,9 +15,6 @@
mc:Ignorable="d" mc:Ignorable="d"
Focusable="True" Focusable="True"
x:DataType="viewModels:UserProfileViewModel"> x:DataType="viewModels:UserProfileViewModel">
<UserControl.Resources>
<helpers:BitmapArrayValueConverter x:Key="ByteImage" />
</UserControl.Resources>
<Design.DataContext> <Design.DataContext>
<viewModels:UserProfileViewModel /> <viewModels:UserProfileViewModel />
</Design.DataContext> </Design.DataContext>
@@ -74,7 +71,7 @@
Height="96" Height="96"
HorizontalAlignment="Stretch" HorizontalAlignment="Stretch"
VerticalAlignment="Top" VerticalAlignment="Top"
Source="{Binding Image, Converter={StaticResource ByteImage}}" /> Source="{Binding Image, Converter={x:Static helpers:BitmapArrayValueConverter.Instance}}" />
<TextBlock <TextBlock
HorizontalAlignment="Stretch" HorizontalAlignment="Stretch"
MaxWidth="90" MaxWidth="90"
+1 -1
View File
@@ -64,7 +64,7 @@ namespace Ryujinx.Ava.UI.Windows
ModLoader.ModCache mods = new(); ModLoader.ModCache mods = new();
ModLoader.QueryContentsDir(mods, new DirectoryInfo(Path.Combine(modsBasePath, "contents")), titleIdValue); ModLoader.QueryContentsDir(mods, new DirectoryInfo(Path.Combine(modsBasePath, "contents")), titleIdValue, []);
string currentCheatFile = string.Empty; string currentCheatFile = string.Empty;
string buildId = string.Empty; string buildId = string.Empty;
+1 -4
View File
@@ -30,9 +30,6 @@
<Design.DataContext> <Design.DataContext>
<viewModels:MainWindowViewModel /> <viewModels:MainWindowViewModel />
</Design.DataContext> </Design.DataContext>
<Window.Resources>
<helpers:BitmapArrayValueConverter x:Key="ByteImage" />
</Window.Resources>
<Window.KeyBindings> <Window.KeyBindings>
<KeyBinding Gesture="Alt+Return" Command="{Binding ToggleFullscreen}" /> <KeyBinding Gesture="Alt+Return" Command="{Binding ToggleFullscreen}" />
<KeyBinding Gesture="F11" Command="{Binding ToggleFullscreen}" /> <KeyBinding Gesture="F11" Command="{Binding ToggleFullscreen}" />
@@ -121,7 +118,7 @@
Width="256" Width="256"
Height="256" Height="256"
IsVisible="{Binding ShowLoadProgress}" IsVisible="{Binding ShowLoadProgress}"
Source="{Binding SelectedIcon, Converter={StaticResource ByteImage}}" /> Source="{Binding SelectedIcon, Converter={x:Static helpers:BitmapArrayValueConverter.Instance}}" />
</Border> </Border>
<Grid <Grid
Grid.Column="1" Grid.Column="1"
@@ -81,7 +81,7 @@
MaxLines="2" MaxLines="2"
TextWrapping="Wrap" TextWrapping="Wrap"
TextTrimming="CharacterEllipsis" TextTrimming="CharacterEllipsis"
Text="{Binding Name}" /> Text="{Binding FormattedName}" />
<StackPanel <StackPanel
Grid.Column="1" Grid.Column="1"
Spacing="10" Spacing="10"
@@ -6,6 +6,7 @@ using Ryujinx.Ava.Common.Locale;
using Ryujinx.Ava.UI.Helpers; using Ryujinx.Ava.UI.Helpers;
using Ryujinx.Ava.UI.Models; using Ryujinx.Ava.UI.Models;
using Ryujinx.Ava.UI.ViewModels; using Ryujinx.Ava.UI.ViewModels;
using Ryujinx.Ava.Utilities.AppLibrary;
using Ryujinx.Common.Helper; using Ryujinx.Common.Helper;
using System.Threading.Tasks; using System.Threading.Tasks;
using Button = Avalonia.Controls.Button; using Button = Avalonia.Controls.Button;
@@ -23,21 +24,21 @@ namespace Ryujinx.Ava.UI.Windows
InitializeComponent(); InitializeComponent();
} }
public ModManagerWindow(ulong titleId) public ModManagerWindow(ulong titleId, ulong titleIdBase, ApplicationLibrary applicationLibrary)
{ {
DataContext = ViewModel = new ModManagerViewModel(titleId); DataContext = ViewModel = new ModManagerViewModel(titleId, titleIdBase, applicationLibrary);
InitializeComponent(); InitializeComponent();
} }
public static async Task Show(ulong titleId, string titleName) public static async Task Show(ulong titleId, ulong titleIdBase, ApplicationLibrary appLibrary, string titleName)
{ {
ContentDialog contentDialog = new() ContentDialog contentDialog = new()
{ {
PrimaryButtonText = string.Empty, PrimaryButtonText = string.Empty,
SecondaryButtonText = string.Empty, SecondaryButtonText = string.Empty,
CloseButtonText = string.Empty, CloseButtonText = string.Empty,
Content = new ModManagerWindow(titleId), Content = new ModManagerWindow(titleId, titleIdBase, appLibrary),
Title = string.Format(LocaleManager.Instance[LocaleKeys.ModWindowTitle], titleName, titleId.ToString("X16")), Title = string.Format(LocaleManager.Instance[LocaleKeys.ModWindowTitle], titleName, titleId.ToString("X16")),
}; };
@@ -34,7 +34,6 @@ namespace Ryujinx.Ava.UI.Windows
#if DEBUG #if DEBUG
this.AttachDevTools(new KeyGesture(Key.F12, KeyModifiers.Alt)); this.AttachDevTools(new KeyGesture(Key.F12, KeyModifiers.Alt));
#endif #endif
} }
public SettingsWindow() public SettingsWindow()
@@ -14,9 +14,6 @@
mc:Ignorable="d" mc:Ignorable="d"
x:DataType="viewModels:TitleUpdateViewModel" x:DataType="viewModels:TitleUpdateViewModel"
Focusable="True"> Focusable="True">
<UserControl.Resources>
<helpers:TitleUpdateLabelConverter x:Key="TitleUpdateLabel" />
</UserControl.Resources>
<Grid RowDefinitions="Auto,*,Auto"> <Grid RowDefinitions="Auto,*,Auto">
<StackPanel <StackPanel
Grid.Row="0" Grid.Row="0"
@@ -57,7 +54,7 @@
VerticalAlignment="Center" VerticalAlignment="Center"
TextWrapping="Wrap"> TextWrapping="Wrap">
<TextBlock.Text> <TextBlock.Text>
<MultiBinding Converter="{StaticResource TitleUpdateLabel}"> <MultiBinding Converter="{x:Static helpers:TitleUpdateLabelConverter.Instance}">
<Binding Path="DisplayVersion" /> <Binding Path="DisplayVersion" />
<Binding Path="IsBundled" /> <Binding Path="IsBundled" />
</MultiBinding> </MultiBinding>
@@ -13,11 +13,6 @@
x:DataType="viewModels:XCITrimmerViewModel" x:DataType="viewModels:XCITrimmerViewModel"
Focusable="True" Focusable="True"
mc:Ignorable="d"> mc:Ignorable="d">
<UserControl.Resources>
<helpers:XCITrimmerFileStatusConverter x:Key="StatusLabel" />
<helpers:XCITrimmerFileStatusDetailConverter x:Key="StatusDetailLabel" />
<helpers:XCITrimmerFileSpaceSavingsConverter x:Key="SpaceSavingsLabel" />
</UserControl.Resources>
<Grid Margin="20 0 20 0"> <Grid Margin="20 0 20 0">
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
@@ -186,7 +181,7 @@
HorizontalAlignment="Left" HorizontalAlignment="Left"
VerticalAlignment="Center" VerticalAlignment="Center"
MaxLines="1" MaxLines="1"
Text="{Binding ., Converter={StaticResource StatusLabel}}"> Text="{Binding ., Converter={x:Static helpers:XCITrimmerFileStatusConverter.Instance}}">
<ToolTip.Tip> <ToolTip.Tip>
<StackPanel <StackPanel
IsVisible="{Binding IsFailed}"> IsVisible="{Binding IsFailed}">
@@ -194,7 +189,7 @@
Classes="h1" Classes="h1"
Text="{ext:Locale XCITrimmerTitleStatusFailed}" /> Text="{ext:Locale XCITrimmerTitleStatusFailed}" />
<TextBlock <TextBlock
Text="{Binding ., Converter={StaticResource StatusDetailLabel}}" Text="{Binding ., Converter={x:Static helpers:XCITrimmerFileStatusDetailConverter.Instance}}"
MaxLines="5" MaxLines="5"
MaxWidth="200" MaxWidth="200"
MaxHeight="100" MaxHeight="100"
@@ -209,7 +204,7 @@
HorizontalAlignment="Left" HorizontalAlignment="Left"
VerticalAlignment="Center" VerticalAlignment="Center"
MaxLines="1" MaxLines="1"
Text="{Binding ., Converter={StaticResource SpaceSavingsLabel}}">> Text="{Binding ., Converter={x:Static helpers:XCITrimmerFileSpaceSavingsConverter.Instance}}">>
</TextBlock> </TextBlock>
</Grid> </Grid>
</Grid> </Grid>
@@ -111,6 +111,30 @@ namespace Ryujinx.Ava.Utilities.AppLibrary
return data; return data;
} }
/// <summary>
/// Gets a name for an available content file based on the Application ID '<paramref name="id"/>'.
/// <br/><br/>
/// For Applications, this returns the localized name of the app found in the file.
/// For DLCs, this returns the name of the file that contains the DLC, minus the file extension.
/// </summary>
/// <param name="id">The Application ID to search for.</param>
/// <remarks>
/// If the provided Application ID does not have a corresponding Application OR DLC file,
/// <paramref name="id"/> formatted as hexadecimal is returned.
/// </remarks>
/// <returns>A formatted Application name, or <paramref name="id"/> as hexadecimal if none is found.</returns>
public string GetNameForApplicationId(ulong id)
{
DynamicData.Kernel.Optional<ApplicationData> appData = Applications.Lookup(id);
if (appData.HasValue)
return appData.Value.Name;
if (DownloadableContents.Keys.FindFirst(x => x.TitleId == id).TryGet(out DownloadableContentModel dlcData))
return dlcData.FileName;
return id.ToString("X16");
}
/// <exception cref="LibHac.Common.Keys.MissingKeyException">The configured key set is missing a key.</exception> /// <exception cref="LibHac.Common.Keys.MissingKeyException">The configured key set is missing a key.</exception>
/// <exception cref="InvalidDataException">The NCA header could not be decrypted.</exception> /// <exception cref="InvalidDataException">The NCA header could not be decrypted.</exception>
/// <exception cref="NotSupportedException">The NCA version is not supported.</exception> /// <exception cref="NotSupportedException">The NCA version is not supported.</exception>
+11
View File
@@ -10,6 +10,7 @@ namespace Ryujinx.Ava.Utilities
public static bool? OverrideDockedMode { get; private set; } public static bool? OverrideDockedMode { get; private set; }
public static bool? OverrideHardwareAcceleration { get; private set; } public static bool? OverrideHardwareAcceleration { get; private set; }
public static string OverrideGraphicsBackend { get; private set; } public static string OverrideGraphicsBackend { get; private set; }
public static string OverrideBackendThreading { get; private set; }
public static string OverrideHideCursor { get; private set; } public static string OverrideHideCursor { get; private set; }
public static string BaseDirPathArg { get; private set; } public static string BaseDirPathArg { get; private set; }
public static string Profile { get; private set; } public static string Profile { get; private set; }
@@ -74,6 +75,16 @@ namespace Ryujinx.Ava.Utilities
OverrideGraphicsBackend = args[++i]; OverrideGraphicsBackend = args[++i];
break; break;
case "--backend-threading":
if (i + 1 >= args.Length)
{
Logger.Error?.Print(LogClass.Application, $"Invalid option '{arg}'");
continue;
}
OverrideBackendThreading = args[++i];
break;
case "-i": case "-i":
case "--application-id": case "--application-id":
LaunchApplicationId = args[++i]; LaunchApplicationId = args[++i];
@@ -1,6 +1,5 @@
using Ryujinx.Ava.Utilities.Configuration.System; using Ryujinx.Ava.Utilities.Configuration.System;
using Ryujinx.Ava.Utilities.Configuration.UI; using Ryujinx.Ava.Utilities.Configuration.UI;
using Ryujinx.Common;
using Ryujinx.Common.Configuration; using Ryujinx.Common.Configuration;
using Ryujinx.Common.Configuration.Hid; using Ryujinx.Common.Configuration.Hid;
using Ryujinx.Common.Configuration.Multiplayer; using Ryujinx.Common.Configuration.Multiplayer;
@@ -8,7 +7,6 @@ using Ryujinx.Common.Logging;
using Ryujinx.Common.Utilities; using Ryujinx.Common.Utilities;
using Ryujinx.HLE; using Ryujinx.HLE;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text.Json.Nodes;
namespace Ryujinx.Ava.Utilities.Configuration namespace Ryujinx.Ava.Utilities.Configuration
{ {
@@ -17,7 +15,7 @@ namespace Ryujinx.Ava.Utilities.Configuration
/// <summary> /// <summary>
/// The current version of the file format /// The current version of the file format
/// </summary> /// </summary>
public const int CurrentVersion = 61; public const int CurrentVersion = 62;
/// <summary> /// <summary>
/// Version of the configuration file format /// Version of the configuration file format
@@ -376,25 +374,16 @@ namespace Ryujinx.Ava.Utilities.Configuration
/// </summary> /// </summary>
public KeyboardHotkeys Hotkeys { get; set; } public KeyboardHotkeys Hotkeys { get; set; }
/// <summary>
/// Legacy keyboard control bindings
/// </summary>
/// <remarks>Kept for file format compatibility (to avoid possible failure when parsing configuration on old versions)</remarks>
/// TODO: Remove this when those older versions aren't in use anymore.
public List<JsonObject> KeyboardConfig { get; set; }
/// <summary>
/// Legacy controller control bindings
/// </summary>
/// <remarks>Kept for file format compatibility (to avoid possible failure when parsing configuration on old versions)</remarks>
/// TODO: Remove this when those older versions aren't in use anymore.
public List<JsonObject> ControllerConfig { get; set; }
/// <summary> /// <summary>
/// Input configurations /// Input configurations
/// </summary> /// </summary>
public List<InputConfig> InputConfig { get; set; } public List<InputConfig> InputConfig { get; set; }
/// <summary>
/// The speed of spectrum cycling for the Rainbow LED feature.
/// </summary>
public float RainbowSpeed { get; set; }
/// <summary> /// <summary>
/// Graphics backend /// Graphics backend
/// </summary> /// </summary>
@@ -140,6 +140,7 @@ namespace Ryujinx.Ava.Utilities.Configuration
Hid.EnableMouse.Value = cff.EnableMouse; Hid.EnableMouse.Value = cff.EnableMouse;
Hid.Hotkeys.Value = cff.Hotkeys; Hid.Hotkeys.Value = cff.Hotkeys;
Hid.InputConfig.Value = cff.InputConfig ?? []; Hid.InputConfig.Value = cff.InputConfig ?? [];
Hid.RainbowSpeed.Value = cff.RainbowSpeed;
Multiplayer.LanInterfaceId.Value = cff.MultiplayerLanInterfaceId; Multiplayer.LanInterfaceId.Value = cff.MultiplayerLanInterfaceId;
Multiplayer.Mode.Value = cff.MultiplayerMode; Multiplayer.Mode.Value = cff.MultiplayerMode;
@@ -427,7 +428,8 @@ namespace Ryujinx.Ava.Utilities.Configuration
LedColor = new Color(255, 5, 1, 253).ToUInt32() LedColor = new Color(255, 5, 1, 253).ToUInt32()
}; };
} }
}) }),
(62, static cff => cff.RainbowSpeed = 1f)
); );
} }
} }
@@ -7,6 +7,7 @@ using Ryujinx.Common.Configuration.Hid;
using Ryujinx.Common.Configuration.Multiplayer; using Ryujinx.Common.Configuration.Multiplayer;
using Ryujinx.Common.Helper; using Ryujinx.Common.Helper;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.Common.Utilities;
using Ryujinx.HLE; using Ryujinx.HLE;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
@@ -445,12 +446,19 @@ namespace Ryujinx.Ava.Utilities.Configuration
/// </summary> /// </summary>
public ReactiveObject<List<InputConfig>> InputConfig { get; private set; } public ReactiveObject<List<InputConfig>> InputConfig { get; private set; }
/// <summary>
/// The speed of spectrum cycling for the Rainbow LED feature.
/// </summary>
public ReactiveObject<float> RainbowSpeed { get; }
public HidSection() public HidSection()
{ {
EnableKeyboard = new ReactiveObject<bool>(); EnableKeyboard = new ReactiveObject<bool>();
EnableMouse = new ReactiveObject<bool>(); EnableMouse = new ReactiveObject<bool>();
Hotkeys = new ReactiveObject<KeyboardHotkeys>(); Hotkeys = new ReactiveObject<KeyboardHotkeys>();
InputConfig = new ReactiveObject<List<InputConfig>>(); InputConfig = new ReactiveObject<List<InputConfig>>();
RainbowSpeed = new ReactiveObject<float>();
RainbowSpeed.Event += (_, args) => Rainbow.Speed = args.NewValue;
} }
} }
@@ -130,9 +130,8 @@ namespace Ryujinx.Ava.Utilities.Configuration
EnableKeyboard = Hid.EnableKeyboard, EnableKeyboard = Hid.EnableKeyboard,
EnableMouse = Hid.EnableMouse, EnableMouse = Hid.EnableMouse,
Hotkeys = Hid.Hotkeys, Hotkeys = Hid.Hotkeys,
KeyboardConfig = [],
ControllerConfig = [],
InputConfig = Hid.InputConfig, InputConfig = Hid.InputConfig,
RainbowSpeed = Hid.RainbowSpeed,
GraphicsBackend = Graphics.GraphicsBackend, GraphicsBackend = Graphics.GraphicsBackend,
PreferredGpu = Graphics.PreferredGpu, PreferredGpu = Graphics.PreferredGpu,
MultiplayerLanInterfaceId = Multiplayer.LanInterfaceId, MultiplayerLanInterfaceId = Multiplayer.LanInterfaceId,
@@ -204,8 +203,8 @@ namespace Ryujinx.Ava.Utilities.Configuration
Multiplayer.LanInterfaceId.Value = "0"; Multiplayer.LanInterfaceId.Value = "0";
Multiplayer.Mode.Value = MultiplayerMode.Disabled; Multiplayer.Mode.Value = MultiplayerMode.Disabled;
Multiplayer.DisableP2p.Value = false; Multiplayer.DisableP2p.Value = false;
Multiplayer.LdnPassphrase.Value = ""; Multiplayer.LdnPassphrase.Value = string.Empty;
Multiplayer.LdnServer.Value = ""; Multiplayer.LdnServer.Value = string.Empty;
UI.GuiColumns.FavColumn.Value = true; UI.GuiColumns.FavColumn.Value = true;
UI.GuiColumns.IconColumn.Value = true; UI.GuiColumns.IconColumn.Value = true;
UI.GuiColumns.AppColumn.Value = true; UI.GuiColumns.AppColumn.Value = true;
@@ -255,6 +254,7 @@ namespace Ryujinx.Ava.Utilities.Configuration
VolumeUp = Key.Unbound, VolumeUp = Key.Unbound,
VolumeDown = Key.Unbound, VolumeDown = Key.Unbound,
}; };
Hid.RainbowSpeed.Value = 1f;
Hid.InputConfig.Value = Hid.InputConfig.Value =
[ [
new StandardKeyboardInputConfig new StandardKeyboardInputConfig