Compare commits

...

15 Commits

Author SHA1 Message Date
Evan Husted
2b06826922 UI: Rework the compatibility list into a Window 2025-03-05 02:08:36 -06:00
Evan Husted
a23c6bf547 misc: chore: [ci skip] fix redundant qualified name 2025-03-04 19:07:39 -06:00
Evan Husted
27cdf876a2 misc: chore: make some cleaner extensions for converting to/from ui/hle enums 2025-03-04 18:24:24 -06:00
Evan Husted
b0c0e8f7ad misc: chore: Move Fs Integrity Checks getter to ConfigurationState 2025-03-04 18:23:57 -06:00
Evan Husted
2317c06364 misc: small Avalonia project restructure
Moved AppLibrary, Configuration, and PlayReport namespaces to Ryujinx.Systems, add the compat list stuff in the base Ryujinx.Systems namespace.
Moved the compatibility UI stuff to the proper UI view/viewmodel folders.
2025-03-04 18:01:48 -06:00
GabCoolGuy
c12a59ecd6 Remove 'About Avalonia' and Replace it with 'About Ryujinx' in MacOS's menu bar (#752)
Video demonstration for non-Mac users:
https://www.youtube.com/watch?v=7Wn_k5AjBuU
2025-03-04 13:23:19 -06:00
Evan Husted
57c22a1f32 misc: chore: [ci skip] Reduce duplicated close button & command space styling for dialogs 2025-03-04 02:57:11 -06:00
Evan Husted
f7976753fd misc: chore: move ThreadedRenderer creation logic into IRenderer base (since ThreadedRenderer is a GAL construct anyways) 2025-03-04 00:14:56 -06:00
Evan Husted
b45a65fbdc misc: chore: rework HLEConfiguration 2025-03-04 00:08:01 -06:00
Evan Husted
c410474d83 misc: chore: Remove MiniCommand 2025-03-02 21:49:58 -06:00
Evan Husted
ffdc419417 misc: chore: [ci skip] small Avalonia project restructure
Moved the Views that existed in the Controls namespace into the Ryujinx.Ava.UI.Views.Misc namespace
Moved UpdateWaitWindow to Ryujinx.Ava.UI.Windows
2025-03-02 21:42:25 -06:00
Evan Husted
da3f4e1d3a misc: Created generic type RyujinxControl to allow for more unified control view model definitions 2025-03-02 21:24:39 -06:00
Evan Husted
69d79322bb misc: chore: remove old title ID constructor for RendererHost 2025-03-02 21:23:36 -06:00
Evan Husted
c3af1dbf1a Stick Visualizer (#579)
![](https://i.imgur.com/iSaXRMr.png)

---------

Co-authored-by: MutantAura <domw0401@gmail.com>
2025-03-02 20:43:31 -06:00
Piplup
10ac381525 compat: Updates (#742)
These are branches i have on my private repo that i been meaning to push
Bluey The Videogame - compatibility/Bluey
Grand Theft Auto: III – The Definitive Edition -
compatibility/gta-definitiveedition
Grand Theft Auto: Vice City – The Definitive Edition -
compatibility/gta-definitiveedition
Grand Theft Auto: San Andreas – The Definitive Edition -
compatibility/gta-definitiveedition
SpongeBob SquarePants: The Cosmic Shake - compatibility/TheCosmicShake

p.s i didn't mess up one of the commit names i swear
2025-03-02 18:39:32 -06:00
145 changed files with 1267 additions and 1053 deletions

View File

@@ -631,6 +631,7 @@
010030D012FF6000,"Bus Driver Simulator",,playable,2022-10-17 13:55:27 010030D012FF6000,"Bus Driver Simulator",,playable,2022-10-17 13:55:27
0100A9101418C000,"BUSTAFELLOWS",nvdec,playable,2020-10-17 20:04:41 0100A9101418C000,"BUSTAFELLOWS",nvdec,playable,2020-10-17 20:04:41
0100177005C8A000,"BUTCHER",,playable,2021-01-11 18:50:17 0100177005C8A000,"BUTCHER",,playable,2021-01-11 18:50:17
01008c2019598000,"Bluey: The Videogame",,playable,2025-02-11 04:38:00
01000B900D8B0000,"Cadence of Hyrule: Crypt of the NecroDancer Featuring The Legend of Zelda",slow;nvdec,playable,2024-04-01 22:43:40 01000B900D8B0000,"Cadence of Hyrule: Crypt of the NecroDancer Featuring The Legend of Zelda",slow;nvdec,playable,2024-04-01 22:43:40
010065700EE06000,"Cadence of Hyrule: Crypt of the NecroDancer Featuring The Legend of Zelda Demo",demo;gpu;nvdec,ingame,2021-02-14 21:48:15 010065700EE06000,"Cadence of Hyrule: Crypt of the NecroDancer Featuring The Legend of Zelda Demo",demo;gpu;nvdec,ingame,2021-02-14 21:48:15
01005C00117A8000,"Café Enchanté",,playable,2020-11-13 14:54:25 01005C00117A8000,"Café Enchanté",,playable,2020-11-13 14:54:25
@@ -1382,6 +1383,9 @@
0100763015C2E000,"Gunvolt Chronicles: Luminous Avenger iX 2",crash;Needs Update,nothing,2022-04-29 15:34:34 0100763015C2E000,"Gunvolt Chronicles: Luminous Avenger iX 2",crash;Needs Update,nothing,2022-04-29 15:34:34
01002C8018554000,"Gurimugurimoa OnceMore Demo",,playable,2022-07-29 22:07:31 01002C8018554000,"Gurimugurimoa OnceMore Demo",,playable,2022-07-29 22:07:31
0100AC601DCA8000,"GYLT",crash,ingame,2024-03-18 20:16:51 0100AC601DCA8000,"GYLT",crash,ingame,2024-03-18 20:16:51
0100c3c012718000,"Grand Theft Auto: III The Definitive Edition",gpu;UE4,ingame,2022-10-31 20:13:52
0100182014022000,"Grand Theft Auto: Vice City The Definitive Edition",gpu;UE4,ingame,2022-10-31 20:13:52
010065a014024000,"Grand Theft Auto: San Andreas The Definitive Edition",gpu;UE4,ingame,2022-10-31 20:13:52
0100822012D76000,"HAAK",gpu,ingame,2023-02-19 14:31:05 0100822012D76000,"HAAK",gpu,ingame,2023-02-19 14:31:05
01007E100EFA8000,"Habroxia",,playable,2020-06-16 23:04:42 01007E100EFA8000,"Habroxia",,playable,2020-06-16 23:04:42
0100535012974000,"Hades",vulkan,playable,2022-10-05 10:45:21 0100535012974000,"Hades",vulkan,playable,2022-10-05 10:45:21
@@ -2729,7 +2733,7 @@
0100C2500FC20000,"Splatoon™ 3",ldn-works;opengl-backend-bug;LAN;amd-vendor-bug,playable,2024-08-04 23:49:11 0100C2500FC20000,"Splatoon™ 3",ldn-works;opengl-backend-bug;LAN;amd-vendor-bug,playable,2024-08-04 23:49:11
0100BA0018500000,"Splatoon™ 3: Splatfest World Premiere",gpu;online-broken;demo,ingame,2022-09-19 03:17:12 0100BA0018500000,"Splatoon™ 3: Splatfest World Premiere",gpu;online-broken;demo,ingame,2022-09-19 03:17:12
010062800D39C000,"SpongeBob SquarePants: Battle for Bikini Bottom - Rehydrated",online-broken;UE4;ldn-broken;vulkan-backend-bug,playable,2023-08-01 19:29:34 010062800D39C000,"SpongeBob SquarePants: Battle for Bikini Bottom - Rehydrated",online-broken;UE4;ldn-broken;vulkan-backend-bug,playable,2023-08-01 19:29:34
01009FB0172F4000,"SpongeBob SquarePants: The Cosmic Shake",gpu;UE4,ingame,2023-08-01 19:29:53 01009FB0172F4000,"SpongeBob SquarePants: The Cosmic Shake",gpu;UE4,ingame,2024-03-04 16:35:00
010097C01336A000,"Spooky Chase",,playable,2022-11-04 12:17:44 010097C01336A000,"Spooky Chase",,playable,2022-11-04 12:17:44
0100C6100D75E000,"Spooky Ghosts Dot Com",,playable,2021-06-15 15:16:11 0100C6100D75E000,"Spooky Ghosts Dot Com",,playable,2021-06-15 15:16:11
0100DE9005170000,"Sports Party",nvdec,playable,2021-03-05 13:40:42 0100DE9005170000,"Sports Party",nvdec,playable,2021-03-05 13:40:42
1 title_id game_name labels status last_updated
631 010030D012FF6000 Bus Driver Simulator playable 2022-10-17 13:55:27
632 0100A9101418C000 BUSTAFELLOWS nvdec playable 2020-10-17 20:04:41
633 0100177005C8A000 BUTCHER playable 2021-01-11 18:50:17
634 01008c2019598000 Bluey: The Videogame playable 2025-02-11 04:38:00
635 01000B900D8B0000 Cadence of Hyrule: Crypt of the NecroDancer Featuring The Legend of Zelda slow;nvdec playable 2024-04-01 22:43:40
636 010065700EE06000 Cadence of Hyrule: Crypt of the NecroDancer Featuring The Legend of Zelda Demo demo;gpu;nvdec ingame 2021-02-14 21:48:15
637 01005C00117A8000 Café Enchanté playable 2020-11-13 14:54:25
1383 0100763015C2E000 Gunvolt Chronicles: Luminous Avenger iX 2 crash;Needs Update nothing 2022-04-29 15:34:34
1384 01002C8018554000 Gurimugurimoa OnceMore Demo playable 2022-07-29 22:07:31
1385 0100AC601DCA8000 GYLT crash ingame 2024-03-18 20:16:51
1386 0100c3c012718000 Grand Theft Auto: III – The Definitive Edition gpu;UE4 ingame 2022-10-31 20:13:52
1387 0100182014022000 Grand Theft Auto: Vice City – The Definitive Edition gpu;UE4 ingame 2022-10-31 20:13:52
1388 010065a014024000 Grand Theft Auto: San Andreas – The Definitive Edition gpu;UE4 ingame 2022-10-31 20:13:52
1389 0100822012D76000 HAAK gpu ingame 2023-02-19 14:31:05
1390 01007E100EFA8000 Habroxia playable 2020-06-16 23:04:42
1391 0100535012974000 Hades vulkan playable 2022-10-05 10:45:21
2733 0100C2500FC20000 Splatoon™ 3 ldn-works;opengl-backend-bug;LAN;amd-vendor-bug playable 2024-08-04 23:49:11
2734 0100BA0018500000 Splatoon™ 3: Splatfest World Premiere gpu;online-broken;demo ingame 2022-09-19 03:17:12
2735 010062800D39C000 SpongeBob SquarePants: Battle for Bikini Bottom - Rehydrated online-broken;UE4;ldn-broken;vulkan-backend-bug playable 2023-08-01 19:29:34
2736 01009FB0172F4000 SpongeBob SquarePants: The Cosmic Shake gpu;UE4 ingame 2023-08-01 19:29:53 2024-03-04 16:35:00
2737 010097C01336A000 Spooky Chase playable 2022-11-04 12:17:44
2738 0100C6100D75E000 Spooky Ghosts Dot Com playable 2021-06-15 15:16:11
2739 0100DE9005170000 Sports Party nvdec playable 2021-03-05 13:40:42

View File

@@ -1,4 +1,6 @@
using Ryujinx.Common.Configuration; using Ryujinx.Common.Configuration;
using Ryujinx.Common.Logging;
using Ryujinx.Graphics.GAL.Multithreading;
using System; using System;
using System.Threading; using System.Threading;
@@ -10,6 +12,20 @@ namespace Ryujinx.Graphics.GAL
bool PreferThreading { get; } bool PreferThreading { get; }
public IRenderer TryMakeThreaded(BackendThreading backendThreading = BackendThreading.Auto)
{
if (backendThreading is BackendThreading.On ||
(backendThreading is BackendThreading.Auto && PreferThreading))
{
Logger.Info?.PrintMsg(LogClass.Gpu, $"Backend Threading ({backendThreading}): True");
return new ThreadedRenderer(this);
}
Logger.Info?.PrintMsg(LogClass.Gpu, $"Backend Threading ({backendThreading}): False");
return this;
}
IPipeline Pipeline { get; } IPipeline Pipeline { get; }
IWindow Window { get; } IWindow Window { get; }

View File

@@ -19,7 +19,7 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator.LdnMitm
private readonly LanDiscovery _lanDiscovery; private readonly LanDiscovery _lanDiscovery;
public LdnMitmClient(HLEConfiguration config) public LdnMitmClient(HleConfiguration config)
{ {
UnicastIPAddressInformation localIpInterface = NetworkHelpers.GetLocalInterface(config.MultiplayerLanInterfaceId).Item2; UnicastIPAddressInformation localIpInterface = NetworkHelpers.GetLocalInterface(config.MultiplayerLanInterfaceId).Item2;

View File

@@ -51,13 +51,13 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator.LdnRyu
private string _passphrase; private string _passphrase;
private byte[] _gameVersion = new byte[0x10]; private byte[] _gameVersion = new byte[0x10];
private readonly HLEConfiguration _config; private readonly HleConfiguration _config;
public event EventHandler<NetworkChangeEventArgs> NetworkChange; public event EventHandler<NetworkChangeEventArgs> NetworkChange;
public ProxyConfig Config { get; private set; } public ProxyConfig Config { get; private set; }
public LdnMasterProxyClient(string address, int port, HLEConfiguration config) : base(address, port) public LdnMasterProxyClient(string address, int port, HleConfiguration config) : base(address, port)
{ {
if (ProxyHelpers.SupportsNoDelay()) if (ProxyHelpers.SupportsNoDelay())
{ {

View File

@@ -15,55 +15,55 @@ namespace Ryujinx.HLE
/// <summary> /// <summary>
/// HLE configuration. /// HLE configuration.
/// </summary> /// </summary>
public class HLEConfiguration public class HleConfiguration
{ {
/// <summary> /// <summary>
/// The virtual file system used by the FS service. /// The virtual file system used by the FS service.
/// </summary> /// </summary>
/// <remarks>This cannot be changed after <see cref="Switch"/> instantiation.</remarks> /// <remarks>This cannot be changed after <see cref="Switch"/> instantiation.</remarks>
internal readonly VirtualFileSystem VirtualFileSystem; internal VirtualFileSystem VirtualFileSystem { get; private set; }
/// <summary> /// <summary>
/// The manager for handling a LibHac Horizon instance. /// The manager for handling a LibHac Horizon instance.
/// </summary> /// </summary>
/// <remarks>This cannot be changed after <see cref="Switch"/> instantiation.</remarks> /// <remarks>This cannot be changed after <see cref="Switch"/> instantiation.</remarks>
internal readonly LibHacHorizonManager LibHacHorizonManager; internal LibHacHorizonManager LibHacHorizonManager { get; private set; }
/// <summary> /// <summary>
/// The account manager used by the account service. /// The account manager used by the account service.
/// </summary> /// </summary>
/// <remarks>This cannot be changed after <see cref="Switch"/> instantiation.</remarks> /// <remarks>This cannot be changed after <see cref="Switch"/> instantiation.</remarks>
internal readonly AccountManager AccountManager; internal AccountManager AccountManager { get; private set; }
/// <summary> /// <summary>
/// The content manager used by the NCM service. /// The content manager used by the NCM service.
/// </summary> /// </summary>
/// <remarks>This cannot be changed after <see cref="Switch"/> instantiation.</remarks> /// <remarks>This cannot be changed after <see cref="Switch"/> instantiation.</remarks>
internal readonly ContentManager ContentManager; internal ContentManager ContentManager { get; private set; }
/// <summary> /// <summary>
/// The persistent information between run for multi-application capabilities. /// The persistent information between run for multi-application capabilities.
/// </summary> /// </summary>
/// <remarks>This cannot be changed after <see cref="Switch"/> instantiation.</remarks> /// <remarks>This cannot be changed after <see cref="Switch"/> instantiation.</remarks>
public readonly UserChannelPersistence UserChannelPersistence; public UserChannelPersistence UserChannelPersistence { get; private set; }
/// <summary> /// <summary>
/// The GPU renderer to use for all GPU operations. /// The GPU renderer to use for all GPU operations.
/// </summary> /// </summary>
/// <remarks>This cannot be changed after <see cref="Switch"/> instantiation.</remarks> /// <remarks>This cannot be changed after <see cref="Switch"/> instantiation.</remarks>
internal readonly IRenderer GpuRenderer; internal IRenderer GpuRenderer { get; private set; }
/// <summary> /// <summary>
/// The audio device driver to use for all audio operations. /// The audio device driver to use for all audio operations.
/// </summary> /// </summary>
/// <remarks>This cannot be changed after <see cref="Switch"/> instantiation.</remarks> /// <remarks>This cannot be changed after <see cref="Switch"/> instantiation.</remarks>
internal readonly IHardwareDeviceDriver AudioDeviceDriver; internal IHardwareDeviceDriver AudioDeviceDriver { get; private set; }
/// <summary> /// <summary>
/// The handler for various UI related operations needed outside of HLE. /// The handler for various UI related operations needed outside of HLE.
/// </summary> /// </summary>
/// <remarks>This cannot be changed after <see cref="Switch"/> instantiation.</remarks> /// <remarks>This cannot be changed after <see cref="Switch"/> instantiation.</remarks>
internal readonly IHostUIHandler HostUIHandler; internal IHostUIHandler HostUIHandler { get; private set; }
/// <summary> /// <summary>
/// Control the memory configuration used by the emulation context. /// Control the memory configuration used by the emulation context.
@@ -195,15 +195,7 @@ namespace Ryujinx.HLE
/// <remarks>This cannot be changed after <see cref="Switch"/> instantiation.</remarks> /// <remarks>This cannot be changed after <see cref="Switch"/> instantiation.</remarks>
public EnabledDirtyHack[] Hacks { internal get; set; } public EnabledDirtyHack[] Hacks { internal get; set; }
public HLEConfiguration(VirtualFileSystem virtualFileSystem, public HleConfiguration(MemoryConfiguration memoryConfiguration,
LibHacHorizonManager libHacHorizonManager,
ContentManager contentManager,
AccountManager accountManager,
UserChannelPersistence userChannelPersistence,
IRenderer gpuRenderer,
IHardwareDeviceDriver audioDeviceDriver,
MemoryConfiguration memoryConfiguration,
IHostUIHandler hostUIHandler,
SystemLanguage systemLanguage, SystemLanguage systemLanguage,
RegionCode region, RegionCode region,
VSyncMode vSyncMode, VSyncMode vSyncMode,
@@ -227,15 +219,7 @@ namespace Ryujinx.HLE
int customVSyncInterval, int customVSyncInterval,
EnabledDirtyHack[] dirtyHacks = null) EnabledDirtyHack[] dirtyHacks = null)
{ {
VirtualFileSystem = virtualFileSystem;
LibHacHorizonManager = libHacHorizonManager;
AccountManager = accountManager;
ContentManager = contentManager;
UserChannelPersistence = userChannelPersistence;
GpuRenderer = gpuRenderer;
AudioDeviceDriver = audioDeviceDriver;
MemoryConfiguration = memoryConfiguration; MemoryConfiguration = memoryConfiguration;
HostUIHandler = hostUIHandler;
SystemLanguage = systemLanguage; SystemLanguage = systemLanguage;
Region = region; Region = region;
VSyncMode = vSyncMode; VSyncMode = vSyncMode;
@@ -259,5 +243,30 @@ namespace Ryujinx.HLE
MultiplayerLdnServer = multiplayerLdnServer; MultiplayerLdnServer = multiplayerLdnServer;
Hacks = dirtyHacks ?? []; Hacks = dirtyHacks ?? [];
} }
/// <summary>
/// Set the pre-configured services to use for this <see cref="HleConfiguration"/> instance.
/// </summary>
public HleConfiguration Configure(
VirtualFileSystem virtualFileSystem,
LibHacHorizonManager libHacHorizonManager,
ContentManager contentManager,
AccountManager accountManager,
UserChannelPersistence userChannelPersistence,
IRenderer gpuRenderer,
IHardwareDeviceDriver audioDeviceDriver,
IHostUIHandler hostUIHandler
)
{
VirtualFileSystem = virtualFileSystem;
LibHacHorizonManager = libHacHorizonManager;
AccountManager = accountManager;
ContentManager = contentManager;
UserChannelPersistence = userChannelPersistence;
GpuRenderer = gpuRenderer;
AudioDeviceDriver = audioDeviceDriver;
HostUIHandler = hostUIHandler;
return this;
}
} }
} }

View File

@@ -20,7 +20,7 @@ namespace Ryujinx.HLE
{ {
public static Switch Shared { get; private set; } public static Switch Shared { get; private set; }
public HLEConfiguration Configuration { get; } public HleConfiguration Configuration { get; }
public IHardwareDeviceDriver AudioDeviceDriver { get; } public IHardwareDeviceDriver AudioDeviceDriver { get; }
public MemoryBlock Memory { get; } public MemoryBlock Memory { get; }
public GpuContext Gpu { get; } public GpuContext Gpu { get; }
@@ -44,7 +44,7 @@ namespace Ryujinx.HLE
public DirtyHacks DirtyHacks { get; } public DirtyHacks DirtyHacks { get; }
public Switch(HLEConfiguration configuration) public Switch(HleConfiguration configuration)
{ {
ArgumentNullException.ThrowIfNull(configuration.GpuRenderer); ArgumentNullException.ThrowIfNull(configuration.GpuRenderer);
ArgumentNullException.ThrowIfNull(configuration.AudioDeviceDriver); ArgumentNullException.ThrowIfNull(configuration.AudioDeviceDriver);
@@ -94,16 +94,20 @@ namespace Ryujinx.HLE
Gpu.GPFifo.DispatchCalls(); Gpu.GPFifo.DispatchCalls();
} }
public void IncrementCustomVSyncInterval() public int IncrementCustomVSyncInterval()
{ {
CustomVSyncInterval += 1; CustomVSyncInterval += 1;
UpdateVSyncInterval(); UpdateVSyncInterval();
return CustomVSyncInterval;
} }
public void DecrementCustomVSyncInterval() public int DecrementCustomVSyncInterval()
{ {
CustomVSyncInterval -= 1; CustomVSyncInterval -= 1;
UpdateVSyncInterval(); UpdateVSyncInterval();
return CustomVSyncInterval;
} }
public void UpdateVSyncInterval() public void UpdateVSyncInterval()

View File

@@ -21,8 +21,8 @@ using Ryujinx.Ava.UI.Renderer;
using Ryujinx.Ava.UI.ViewModels; using Ryujinx.Ava.UI.ViewModels;
using Ryujinx.Ava.UI.Windows; using Ryujinx.Ava.UI.Windows;
using Ryujinx.Ava.Utilities; using Ryujinx.Ava.Utilities;
using Ryujinx.Ava.Utilities.AppLibrary; using Ryujinx.Ava.Systems.AppLibrary;
using Ryujinx.Ava.Utilities.Configuration; using Ryujinx.Ava.Systems.Configuration;
using Ryujinx.Common; using Ryujinx.Common;
using Ryujinx.Common.Configuration; using Ryujinx.Common.Configuration;
using Ryujinx.Common.Configuration.Multiplayer; using Ryujinx.Common.Configuration.Multiplayer;
@@ -902,53 +902,19 @@ namespace Ryujinx.Ava
_ => new OpenGLRenderer() _ => new OpenGLRenderer()
}; };
BackendThreading threadingMode = ConfigurationState.Instance.Graphics.BackendThreading;
bool isGALThreaded = threadingMode == BackendThreading.On || (threadingMode == BackendThreading.Auto && renderer.PreferThreading);
if (isGALThreaded)
{
renderer = new ThreadedRenderer(renderer);
}
Logger.Info?.PrintMsg(LogClass.Gpu, $"Backend Threading ({threadingMode}): {isGALThreaded}");
// Initialize Configuration. // Initialize Configuration.
MemoryConfiguration memoryConfiguration = ConfigurationState.Instance.System.DramSize.Value; Device = new Switch(ConfigurationState.Instance.CreateHleConfiguration()
.Configure(
Device = new Switch(new HLEConfiguration( VirtualFileSystem,
VirtualFileSystem, _viewModel.LibHacHorizonManager,
_viewModel.LibHacHorizonManager, ContentManager,
ContentManager, _accountManager,
_accountManager, _userChannelPersistence,
_userChannelPersistence, renderer.TryMakeThreaded(ConfigurationState.Instance.Graphics.BackendThreading),
renderer, InitializeAudio(),
InitializeAudio(), _viewModel.UiHandler
memoryConfiguration, )
_viewModel.UiHandler, );
(SystemLanguage)ConfigurationState.Instance.System.Language.Value,
(RegionCode)ConfigurationState.Instance.System.Region.Value,
ConfigurationState.Instance.Graphics.VSyncMode,
ConfigurationState.Instance.System.EnableDockedMode,
ConfigurationState.Instance.System.EnablePtc,
ConfigurationState.Instance.System.EnableInternetAccess,
ConfigurationState.Instance.System.EnableFsIntegrityChecks ? IntegrityCheckLevel.ErrorOnInvalid : IntegrityCheckLevel.None,
ConfigurationState.Instance.System.FsGlobalAccessLogMode,
ConfigurationState.Instance.System.MatchSystemTime
? 0
: ConfigurationState.Instance.System.SystemTimeOffset,
ConfigurationState.Instance.System.TimeZone,
ConfigurationState.Instance.System.MemoryManagerMode,
ConfigurationState.Instance.System.IgnoreMissingServices,
ConfigurationState.Instance.Graphics.AspectRatio,
ConfigurationState.Instance.System.AudioVolume,
ConfigurationState.Instance.System.UseHypervisor,
ConfigurationState.Instance.Multiplayer.LanInterfaceId.Value,
ConfigurationState.Instance.Multiplayer.Mode,
ConfigurationState.Instance.Multiplayer.DisableP2p,
ConfigurationState.Instance.Multiplayer.LdnPassphrase,
ConfigurationState.Instance.Multiplayer.GetLdnServer(),
ConfigurationState.Instance.Graphics.CustomVSyncInterval.Value,
ConfigurationState.Instance.Hacks.ShowDirtyHacks ? ConfigurationState.Instance.Hacks.EnabledHacks : null));
} }
private static IHardwareDeviceDriver InitializeAudio() private static IHardwareDeviceDriver InitializeAudio()
@@ -1182,6 +1148,9 @@ namespace Ryujinx.Ava
private void UpdateShaderCount() private void UpdateShaderCount()
{ {
if (_displayCount is 0 && _renderer.ProgramCount is 0)
return;
// If there is a mismatch between total program compile and previous count // If there is a mismatch between total program compile and previous count
// this means new shaders have been compiled and should be displayed. // this means new shaders have been compiled and should be displayed.
if (_renderer.ProgramCount != _previousCount) if (_renderer.ProgramCount != _previousCount)
@@ -1255,12 +1224,10 @@ namespace Ryujinx.Ava
VSyncModeToggle(); VSyncModeToggle();
break; break;
case KeyboardHotkeyState.CustomVSyncIntervalDecrement: case KeyboardHotkeyState.CustomVSyncIntervalDecrement:
Device.DecrementCustomVSyncInterval(); _viewModel.CustomVSyncInterval = Device.DecrementCustomVSyncInterval();
_viewModel.CustomVSyncInterval -= 1;
break; break;
case KeyboardHotkeyState.CustomVSyncIntervalIncrement: case KeyboardHotkeyState.CustomVSyncIntervalIncrement:
Device.IncrementCustomVSyncInterval(); _viewModel.CustomVSyncInterval = Device.IncrementCustomVSyncInterval();
_viewModel.CustomVSyncInterval += 1;
break; break;
case KeyboardHotkeyState.Screenshot: case KeyboardHotkeyState.Screenshot:
ScreenshotRequested = true; ScreenshotRequested = true;

View File

@@ -440,7 +440,7 @@
<x:Double x:Key="ControlContentThemeFontSize">13</x:Double> <x:Double x:Key="ControlContentThemeFontSize">13</x:Double>
<x:Double x:Key="MenuItemHeight">26</x:Double> <x:Double x:Key="MenuItemHeight">26</x:Double>
<x:Double x:Key="TabItemMinHeight">28</x:Double> <x:Double x:Key="TabItemMinHeight">28</x:Double>
<x:Double x:Key="ContentDialogMaxWidth">900</x:Double> <x:Double x:Key="ContentDialogMaxWidth">700</x:Double>
<x:Double x:Key="ContentDialogMaxHeight">756</x:Double> <x:Double x:Key="ContentDialogMaxHeight">756</x:Double>
</Styles.Resources> </Styles.Resources>
</Styles> </Styles>

View File

@@ -23822,6 +23822,31 @@
"zh_TW": "上次更新時間: {0}" "zh_TW": "上次更新時間: {0}"
} }
}, },
{
"ID": "CompatibilityListTitle",
"Translations": {
"ar_SA": "",
"de_DE": "",
"el_GR": "",
"en_US": "Compatibility List - {0} entries",
"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": "CompatibilityListWarning", "ID": "CompatibilityListWarning",
"Translations": { "Translations": {
@@ -23872,6 +23897,31 @@
"zh_TW": "搜尋相容性列表紀錄..." "zh_TW": "搜尋相容性列表紀錄..."
} }
}, },
{
"ID": "CompatibilityListSearchBoxWatermarkWithCount",
"Translations": {
"ar_SA": "",
"de_DE": "",
"el_GR": "",
"en_US": "Search {0} compatibility entries...",
"es_ES": "",
"fr_FR": "",
"he_IL": "",
"it_IT": "",
"ja_JP": "",
"ko_KR": "",
"no_NO": "Søk i {0} kompatibilitetsoppføringer...",
"pl_PL": "",
"pt_BR": "",
"ru_RU": "",
"sv_SE": "",
"th_TH": "",
"tr_TR": "",
"uk_UA": "",
"zh_CN": "",
"zh_TW": ""
}
},
{ {
"ID": "CompatibilityListOpen", "ID": "CompatibilityListOpen",
"Translations": { "Translations": {

View File

@@ -13,10 +13,10 @@ using LibHac.Tools.Fs;
using LibHac.Tools.FsSystem; using LibHac.Tools.FsSystem;
using LibHac.Tools.FsSystem.NcaUtils; using LibHac.Tools.FsSystem.NcaUtils;
using Ryujinx.Ava.Common.Locale; using Ryujinx.Ava.Common.Locale;
using Ryujinx.Ava.UI.Controls; using Ryujinx.Ava.UI.Windows;
using Ryujinx.Ava.UI.Helpers; using Ryujinx.Ava.UI.Helpers;
using Ryujinx.Ava.Utilities; using Ryujinx.Ava.Utilities;
using Ryujinx.Ava.Utilities.Configuration; using Ryujinx.Ava.Systems.Configuration;
using Ryujinx.Common.Helper; using Ryujinx.Common.Helper;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.HLE.FileSystem; using Ryujinx.HLE.FileSystem;
@@ -216,11 +216,7 @@ namespace Ryujinx.Ava.Common
return; return;
} }
IntegrityCheckLevel checkLevel = ConfigurationState.Instance.System.EnableFsIntegrityChecks (Nca updatePatchNca, _) = mainNca.GetUpdateData(_virtualFileSystem, ConfigurationState.Instance.System.IntegrityCheckLevel, programIndex, out _);
? IntegrityCheckLevel.ErrorOnInvalid
: IntegrityCheckLevel.None;
(Nca updatePatchNca, _) = mainNca.GetUpdateData(_virtualFileSystem, checkLevel, programIndex, out _);
if (updatePatchNca is not null) if (updatePatchNca is not null)
{ {
patchNca = updatePatchNca; patchNca = updatePatchNca;

View File

@@ -1,6 +1,7 @@
using Gommon; using Gommon;
using Ryujinx.Ava.Systems;
using Ryujinx.Ava.UI.ViewModels; using Ryujinx.Ava.UI.ViewModels;
using Ryujinx.Ava.Utilities.Configuration; using Ryujinx.Ava.Systems.Configuration;
using Ryujinx.Common; using Ryujinx.Common;
using Ryujinx.Common.Utilities; using Ryujinx.Common.Utilities;
using System; using System;
@@ -55,6 +56,8 @@ namespace Ryujinx.Ava.Common.Locale
SetDynamicValues(LocaleKeys.RyujinxConfirm, RyujinxApp.FullAppName); SetDynamicValues(LocaleKeys.RyujinxConfirm, RyujinxApp.FullAppName);
SetDynamicValues(LocaleKeys.RyujinxUpdater, RyujinxApp.FullAppName); SetDynamicValues(LocaleKeys.RyujinxUpdater, RyujinxApp.FullAppName);
SetDynamicValues(LocaleKeys.RyujinxRebooter, RyujinxApp.FullAppName); SetDynamicValues(LocaleKeys.RyujinxRebooter, RyujinxApp.FullAppName);
SetDynamicValues(LocaleKeys.CompatibilityListSearchBoxWatermarkWithCount, CompatibilityCsv.Entries.Length);
} }
public string this[LocaleKeys key] public string this[LocaleKeys key]

View File

@@ -1,4 +1,4 @@
using Ryujinx.Ava.Utilities.AppLibrary; using Ryujinx.Ava.Systems.AppLibrary;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.Common.Utilities; using Ryujinx.Common.Utilities;

View File

@@ -1,9 +1,9 @@
using DiscordRPC; using DiscordRPC;
using Gommon; using Gommon;
using Ryujinx.Ava.Utilities; using Ryujinx.Ava.Utilities;
using Ryujinx.Ava.Utilities.AppLibrary; using Ryujinx.Ava.Systems.AppLibrary;
using Ryujinx.Ava.Utilities.Configuration; using Ryujinx.Ava.Systems.Configuration;
using Ryujinx.Ava.Utilities.PlayReport; using Ryujinx.Ava.Systems.PlayReport;
using Ryujinx.Common; using Ryujinx.Common;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.HLE; using Ryujinx.HLE;

View File

@@ -2,7 +2,7 @@ using DiscordRPC;
using LibHac.Tools.FsSystem; using LibHac.Tools.FsSystem;
using Ryujinx.Audio.Backends.SDL2; using Ryujinx.Audio.Backends.SDL2;
using Ryujinx.Ava; using Ryujinx.Ava;
using Ryujinx.Ava.Utilities.Configuration; using Ryujinx.Ava.Systems.Configuration;
using Ryujinx.Common.Configuration; using Ryujinx.Common.Configuration;
using Ryujinx.Common.Configuration.Hid; using Ryujinx.Common.Configuration.Hid;
using Ryujinx.Common.Configuration.Hid.Controller; using Ryujinx.Common.Configuration.Hid.Controller;
@@ -312,49 +312,42 @@ namespace Ryujinx.Headless
return new OpenGLRenderer(); return new OpenGLRenderer();
} }
private static Switch InitializeEmulationContext(WindowBase window, IRenderer renderer, Options options) private static Switch InitializeEmulationContext(WindowBase window, IRenderer renderer, Options options) =>
{ new(
BackendThreading threadingMode = options.BackendThreading; new HleConfiguration(
options.DramSize,
bool threadedGAL = threadingMode == BackendThreading.On || (threadingMode == BackendThreading.Auto && renderer.PreferThreading); options.SystemLanguage,
options.SystemRegion,
if (threadedGAL) options.VSyncMode,
{ !options.DisableDockedMode,
renderer = new ThreadedRenderer(renderer); !options.DisablePTC,
} options.EnableInternetAccess,
!options.DisableFsIntegrityChecks ? IntegrityCheckLevel.ErrorOnInvalid : IntegrityCheckLevel.None,
HLEConfiguration configuration = new(_virtualFileSystem, options.FsGlobalAccessLogMode,
_libHacHorizonManager, options.SystemTimeOffset,
_contentManager, options.SystemTimeZone,
_accountManager, options.MemoryManagerMode,
_userChannelPersistence, options.IgnoreMissingServices,
renderer, options.AspectRatio,
new SDL2HardwareDeviceDriver(), options.AudioVolume,
options.DramSize, options.UseHypervisor ?? true,
window, options.MultiplayerLanInterfaceId,
options.SystemLanguage, Common.Configuration.Multiplayer.MultiplayerMode.Disabled,
options.SystemRegion, false,
options.VSyncMode, string.Empty,
!options.DisableDockedMode, string.Empty,
!options.DisablePTC, options.CustomVSyncInterval
options.EnableInternetAccess, )
!options.DisableFsIntegrityChecks ? IntegrityCheckLevel.ErrorOnInvalid : IntegrityCheckLevel.None, .Configure(
options.FsGlobalAccessLogMode, _virtualFileSystem,
options.SystemTimeOffset, _libHacHorizonManager,
options.SystemTimeZone, _contentManager,
options.MemoryManagerMode, _accountManager,
options.IgnoreMissingServices, _userChannelPersistence,
options.AspectRatio, renderer.TryMakeThreaded(options.BackendThreading),
options.AudioVolume, new SDL2HardwareDeviceDriver(),
options.UseHypervisor ?? true, window
options.MultiplayerLanInterfaceId, )
Common.Configuration.Multiplayer.MultiplayerMode.Disabled, );
false,
string.Empty,
string.Empty,
options.CustomVSyncInterval);
return new Switch(configuration);
}
} }
} }

View File

@@ -1,7 +1,7 @@
using CommandLine; using CommandLine;
using Gommon; using Gommon;
using Ryujinx.Ava; using Ryujinx.Ava;
using Ryujinx.Ava.Utilities.Configuration; using Ryujinx.Ava.Systems.Configuration;
using Ryujinx.Common; using Ryujinx.Common;
using Ryujinx.Common.Configuration; using Ryujinx.Common.Configuration;
using Ryujinx.Common.Configuration.Hid; using Ryujinx.Common.Configuration.Hid;

View File

@@ -1,6 +1,7 @@
using CommandLine; using CommandLine;
using Gommon; using Gommon;
using Ryujinx.Ava.Utilities.Configuration; using Ryujinx.Ava.Systems.Configuration;
using Ryujinx.Ava.Systems.Configuration.System;
using Ryujinx.Common.Configuration; using Ryujinx.Common.Configuration;
using Ryujinx.Common.Configuration.Hid; using Ryujinx.Common.Configuration.Hid;
using Ryujinx.HLE; using Ryujinx.HLE;
@@ -37,7 +38,7 @@ namespace Ryujinx.Headless
EnableInternetAccess = configurationState.System.EnableInternetAccess; EnableInternetAccess = configurationState.System.EnableInternetAccess;
if (NeedsOverride(nameof(DisableFsIntegrityChecks))) if (NeedsOverride(nameof(DisableFsIntegrityChecks)))
DisableFsIntegrityChecks = configurationState.System.EnableFsIntegrityChecks; DisableFsIntegrityChecks = !configurationState.System.EnableFsIntegrityChecks;
if (NeedsOverride(nameof(FsGlobalAccessLogMode))) if (NeedsOverride(nameof(FsGlobalAccessLogMode)))
FsGlobalAccessLogMode = configurationState.System.FsGlobalAccessLogMode; FsGlobalAccessLogMode = configurationState.System.FsGlobalAccessLogMode;
@@ -58,10 +59,10 @@ namespace Ryujinx.Headless
DisableDockedMode = !configurationState.System.EnableDockedMode; DisableDockedMode = !configurationState.System.EnableDockedMode;
if (NeedsOverride(nameof(SystemLanguage))) if (NeedsOverride(nameof(SystemLanguage)))
SystemLanguage = (SystemLanguage)(int)configurationState.System.Language.Value; SystemLanguage = configurationState.System.Language.Value.ToHLE();
if (NeedsOverride(nameof(SystemRegion))) if (NeedsOverride(nameof(SystemRegion)))
SystemRegion = (RegionCode)(int)configurationState.System.Region.Value; SystemRegion = configurationState.System.Region.Value.ToHLE();
if (NeedsOverride(nameof(SystemTimeZone))) if (NeedsOverride(nameof(SystemTimeZone)))
SystemTimeZone = configurationState.System.TimeZone; SystemTimeZone = configurationState.System.TimeZone;

View File

@@ -8,7 +8,8 @@ using Projektanker.Icons.Avalonia.MaterialDesign;
using Ryujinx.Ava.UI.Helpers; using Ryujinx.Ava.UI.Helpers;
using Ryujinx.Ava.UI.Windows; using Ryujinx.Ava.UI.Windows;
using Ryujinx.Ava.Utilities; using Ryujinx.Ava.Utilities;
using Ryujinx.Ava.Utilities.Configuration; using Ryujinx.Ava.Systems.Configuration;
using Ryujinx.Ava.Systems.Configuration.System;
using Ryujinx.Ava.Utilities.SystemInfo; using Ryujinx.Ava.Utilities.SystemInfo;
using Ryujinx.Common; using Ryujinx.Common;
using Ryujinx.Common.Configuration; using Ryujinx.Common.Configuration;
@@ -282,16 +283,16 @@ namespace Ryujinx.Ava
// Check if region was overridden. // Check if region was overridden.
if (CommandLineState.OverrideSystemRegion is not null) if (CommandLineState.OverrideSystemRegion is not null)
if (Enum.TryParse(CommandLineState.OverrideSystemRegion, true, out Ryujinx.HLE.HOS.SystemState.RegionCode result)) if (Enum.TryParse(CommandLineState.OverrideSystemRegion, true, out HLE.HOS.SystemState.RegionCode result))
{ {
ConfigurationState.Instance.System.Region.Value = (Utilities.Configuration.System.Region)result; ConfigurationState.Instance.System.Region.Value = result.ToUI();
} }
//Check if language was overridden. //Check if language was overridden.
if (CommandLineState.OverrideSystemLanguage is not null) if (CommandLineState.OverrideSystemLanguage is not null)
if (Enum.TryParse(CommandLineState.OverrideSystemLanguage, true, out Ryujinx.HLE.HOS.SystemState.SystemLanguage result)) if (Enum.TryParse(CommandLineState.OverrideSystemLanguage, true, out HLE.HOS.SystemState.SystemLanguage result))
{ {
ConfigurationState.Instance.System.Language.Value = (Utilities.Configuration.System.Language)result; ConfigurationState.Instance.System.Language.Value = result.ToUI();
} }
// Check if hardware-acceleration was overridden. // Check if hardware-acceleration was overridden.

View File

@@ -17,4 +17,9 @@
<sty:FluentAvaloniaTheme PreferUserAccentColor="True" PreferSystemTheme="False" /> <sty:FluentAvaloniaTheme PreferUserAccentColor="True" PreferSystemTheme="False" />
<StyleInclude Source="/Assets/Styles/Styles.xaml" /> <StyleInclude Source="/Assets/Styles/Styles.xaml" />
</Application.Styles> </Application.Styles>
<NativeMenu.Menu>
<NativeMenu>
<NativeMenuItem Header="About Ryujinx" Click="AboutRyujinx_OnClick" />
</NativeMenu>
</NativeMenu.Menu>
</Application> </Application>

View File

@@ -12,7 +12,7 @@ using Ryujinx.Ava.Common.Locale;
using Ryujinx.Ava.UI.Helpers; using Ryujinx.Ava.UI.Helpers;
using Ryujinx.Ava.UI.Windows; using Ryujinx.Ava.UI.Windows;
using Ryujinx.Ava.Utilities; using Ryujinx.Ava.Utilities;
using Ryujinx.Ava.Utilities.Configuration; using Ryujinx.Ava.Systems.Configuration;
using Ryujinx.Common; using Ryujinx.Common;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using System; using System;
@@ -147,5 +147,10 @@ namespace Ryujinx.Ava
Current is RyujinxApp { PlatformSettings: not null } app Current is RyujinxApp { PlatformSettings: not null } app
? ConvertThemeVariant(app.PlatformSettings.GetColorValues().ThemeVariant) ? ConvertThemeVariant(app.PlatformSettings.GetColorValues().ThemeVariant)
: ThemeVariant.Default; : ThemeVariant.Default;
private async void AboutRyujinx_OnClick(object sender, EventArgs e)
{
await AboutWindow.Show();
}
} }
} }

View File

@@ -1,6 +1,6 @@
using System; using System;
namespace Ryujinx.Ava.Utilities.AppLibrary namespace Ryujinx.Ava.Systems.AppLibrary
{ {
public class ApplicationCountUpdatedEventArgs : EventArgs public class ApplicationCountUpdatedEventArgs : EventArgs
{ {

View File

@@ -9,8 +9,8 @@ using LibHac.Tools.Fs;
using LibHac.Tools.FsSystem; using LibHac.Tools.FsSystem;
using LibHac.Tools.FsSystem.NcaUtils; using LibHac.Tools.FsSystem.NcaUtils;
using Ryujinx.Ava.Common.Locale; using Ryujinx.Ava.Common.Locale;
using Ryujinx.Ava.Utilities.Compat; using Ryujinx.Ava.Utilities;
using Ryujinx.Ava.Utilities.PlayReport; using Ryujinx.Ava.Systems.PlayReport;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.HLE.FileSystem; using Ryujinx.HLE.FileSystem;
using Ryujinx.HLE.Loaders.Processes.Extensions; using Ryujinx.HLE.Loaders.Processes.Extensions;
@@ -18,7 +18,7 @@ using System;
using System.IO; using System.IO;
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
namespace Ryujinx.Ava.Utilities.AppLibrary namespace Ryujinx.Ava.Systems.AppLibrary
{ {
public class ApplicationData public class ApplicationData
{ {

View File

@@ -1,6 +1,6 @@
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
namespace Ryujinx.Ava.Utilities.AppLibrary namespace Ryujinx.Ava.Systems.AppLibrary
{ {
[JsonSourceGenerationOptions(WriteIndented = true)] [JsonSourceGenerationOptions(WriteIndented = true)]
[JsonSerializable(typeof(ApplicationMetadata))] [JsonSerializable(typeof(ApplicationMetadata))]

View File

@@ -12,8 +12,9 @@ using LibHac.Tools.Fs;
using LibHac.Tools.FsSystem; using LibHac.Tools.FsSystem;
using LibHac.Tools.FsSystem.NcaUtils; using LibHac.Tools.FsSystem.NcaUtils;
using Ryujinx.Ava.Common.Models; using Ryujinx.Ava.Common.Models;
using Ryujinx.Ava.Utilities.Configuration; using Ryujinx.Ava.Utilities;
using Ryujinx.Ava.Utilities.Configuration.System; using Ryujinx.Ava.Systems.Configuration;
using Ryujinx.Ava.Systems.Configuration.System;
using Ryujinx.Common; using Ryujinx.Common;
using Ryujinx.Common.Configuration; using Ryujinx.Common.Configuration;
using Ryujinx.Common.Configuration.Multiplayer; using Ryujinx.Common.Configuration.Multiplayer;
@@ -38,7 +39,7 @@ using MissingKeyException = LibHac.Common.Keys.MissingKeyException;
using Path = System.IO.Path; using Path = System.IO.Path;
using TimeSpan = System.TimeSpan; using TimeSpan = System.TimeSpan;
namespace Ryujinx.Ava.Utilities.AppLibrary namespace Ryujinx.Ava.Systems.AppLibrary
{ {
public class ApplicationLibrary public class ApplicationLibrary
{ {
@@ -617,15 +618,11 @@ namespace Ryujinx.Ava.Utilities.AppLibrary
case ".xci": case ".xci":
case ".nsp": case ".nsp":
{ {
IntegrityCheckLevel checkLevel = ConfigurationState.Instance.System.EnableFsIntegrityChecks
? IntegrityCheckLevel.ErrorOnInvalid
: IntegrityCheckLevel.None;
using IFileSystem pfs = using IFileSystem pfs =
PartitionFileSystemUtils.OpenApplicationFileSystem(filePath, _virtualFileSystem); PartitionFileSystemUtils.OpenApplicationFileSystem(filePath, _virtualFileSystem);
Dictionary<ulong, ContentMetaData> updates = Dictionary<ulong, ContentMetaData> updates =
pfs.GetContentData(ContentMetaType.Patch, _virtualFileSystem, checkLevel); pfs.GetContentData(ContentMetaType.Patch, _virtualFileSystem, ConfigurationState.Instance.System.IntegrityCheckLevel);
if (updates.Count == 0) if (updates.Count == 0)
{ {

View File

@@ -1,7 +1,7 @@
using System; using System;
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
namespace Ryujinx.Ava.Utilities.AppLibrary namespace Ryujinx.Ava.Systems.AppLibrary
{ {
public class ApplicationMetadata public class ApplicationMetadata
{ {

View File

@@ -4,7 +4,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
namespace Ryujinx.Ava.Utilities.AppLibrary namespace Ryujinx.Ava.Systems.AppLibrary
{ {
public struct LdnGameData public struct LdnGameData
{ {

View File

@@ -1,7 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
namespace Ryujinx.Ava.Utilities.AppLibrary namespace Ryujinx.Ava.Systems.AppLibrary
{ {
public class LdnGameDataReceivedEventArgs : EventArgs public class LdnGameDataReceivedEventArgs : EventArgs
{ {

View File

@@ -1,7 +1,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
namespace Ryujinx.Ava.Utilities.AppLibrary namespace Ryujinx.Ava.Systems.AppLibrary
{ {
[JsonSerializable(typeof(IEnumerable<LdnGameData>))] [JsonSerializable(typeof(IEnumerable<LdnGameData>))]
internal partial class LdnGameDataSerializerContext : JsonSerializerContext; internal partial class LdnGameDataSerializerContext : JsonSerializerContext;

View File

@@ -9,7 +9,7 @@ using System.Linq;
using System.Reflection; using System.Reflection;
using System.Text; using System.Text;
namespace Ryujinx.Ava.Utilities.Compat namespace Ryujinx.Ava.Systems
{ {
public struct ColumnIndices(Func<ReadOnlySpan<char>, int> getIndex) public struct ColumnIndices(Func<ReadOnlySpan<char>, int> getIndex)
{ {

View File

@@ -1,7 +1,7 @@
using Ryujinx.Common.Utilities; using Ryujinx.Common.Utilities;
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
namespace Ryujinx.Ava.Utilities.Configuration namespace Ryujinx.Ava.Systems.Configuration
{ {
[JsonConverter(typeof(TypedStringEnumConverter<AudioBackend>))] [JsonConverter(typeof(TypedStringEnumConverter<AudioBackend>))]
public enum AudioBackend public enum AudioBackend

View File

@@ -1,5 +1,5 @@
using Ryujinx.Ava.Utilities.Configuration.System; using Ryujinx.Ava.Systems.Configuration.System;
using Ryujinx.Ava.Utilities.Configuration.UI; using Ryujinx.Ava.Systems.Configuration.UI;
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 +8,7 @@ using Ryujinx.Common.Utilities;
using Ryujinx.HLE; using Ryujinx.HLE;
using System.Collections.Generic; using System.Collections.Generic;
namespace Ryujinx.Ava.Utilities.Configuration namespace Ryujinx.Ava.Systems.Configuration
{ {
public class ConfigurationFileFormat public class ConfigurationFileFormat
{ {

View File

@@ -1,6 +1,6 @@
using Ryujinx.Common.Utilities; using Ryujinx.Common.Utilities;
namespace Ryujinx.Ava.Utilities.Configuration namespace Ryujinx.Ava.Systems.Configuration
{ {
internal static class ConfigurationFileFormatSettings internal static class ConfigurationFileFormatSettings
{ {

View File

@@ -1,6 +1,6 @@
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
namespace Ryujinx.Ava.Utilities.Configuration namespace Ryujinx.Ava.Systems.Configuration
{ {
[JsonSourceGenerationOptions(WriteIndented = true)] [JsonSourceGenerationOptions(WriteIndented = true)]
[JsonSerializable(typeof(ConfigurationFileFormat))] [JsonSerializable(typeof(ConfigurationFileFormat))]

View File

@@ -1,7 +1,7 @@
using Avalonia.Media; using Avalonia.Media;
using Gommon; using Gommon;
using Ryujinx.Ava.Utilities.Configuration.System; using Ryujinx.Ava.Systems.Configuration.System;
using Ryujinx.Ava.Utilities.Configuration.UI; using Ryujinx.Ava.Systems.Configuration.UI;
using Ryujinx.Common.Configuration; using Ryujinx.Common.Configuration;
using Ryujinx.Common.Configuration.Hid; using Ryujinx.Common.Configuration.Hid;
using Ryujinx.Common.Configuration.Hid.Controller; using Ryujinx.Common.Configuration.Hid.Controller;
@@ -14,7 +14,7 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using RyuLogger = Ryujinx.Common.Logging.Logger; using RyuLogger = Ryujinx.Common.Logging.Logger;
namespace Ryujinx.Ava.Utilities.Configuration namespace Ryujinx.Ava.Systems.Configuration
{ {
public partial class ConfigurationState public partial class ConfigurationState
{ {

View File

@@ -1,8 +1,8 @@
using ARMeilleure; using ARMeilleure;
using Gommon; using Gommon;
using Ryujinx.Ava.Utilities.AppLibrary; using LibHac.Tools.FsSystem;
using Ryujinx.Ava.Utilities.Configuration.System; using Ryujinx.Ava.Systems.Configuration.System;
using Ryujinx.Ava.Utilities.Configuration.UI; using Ryujinx.Ava.Systems.Configuration.UI;
using Ryujinx.Common; using Ryujinx.Common;
using Ryujinx.Common.Configuration; using Ryujinx.Common.Configuration;
using Ryujinx.Common.Configuration.Hid; using Ryujinx.Common.Configuration.Hid;
@@ -11,15 +11,16 @@ using Ryujinx.Common.Helper;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.Common.Utilities; using Ryujinx.Common.Utilities;
using Ryujinx.HLE; using Ryujinx.HLE;
using Ryujinx.HLE.HOS.SystemState;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using RyuLogger = Ryujinx.Common.Logging.Logger; using RyuLogger = Ryujinx.Common.Logging.Logger;
namespace Ryujinx.Ava.Utilities.Configuration namespace Ryujinx.Ava.Systems.Configuration
{ {
public partial class ConfigurationState public partial class ConfigurationState
{ {
/// <summary> /// <summary>
/// UI configuration section /// UI configuration section
/// </summary> /// </summary>
public class UISection public class UISection
@@ -351,6 +352,10 @@ namespace Ryujinx.Ava.Utilities.Configuration
/// </summary> /// </summary>
public ReactiveObject<bool> EnableFsIntegrityChecks { get; private set; } public ReactiveObject<bool> EnableFsIntegrityChecks { get; private set; }
public IntegrityCheckLevel IntegrityCheckLevel => EnableFsIntegrityChecks
? IntegrityCheckLevel.ErrorOnInvalid
: IntegrityCheckLevel.None;
/// <summary> /// <summary>
/// Enables FS access log output to the console. Possible modes are 0-3 /// Enables FS access log output to the console. Possible modes are 0-3
/// </summary> /// </summary>
@@ -838,5 +843,35 @@ namespace Ryujinx.Ava.Utilities.Configuration
EnableHardwareAcceleration = new ReactiveObject<bool>(); EnableHardwareAcceleration = new ReactiveObject<bool>();
HideCursor = new ReactiveObject<HideCursorMode>(); HideCursor = new ReactiveObject<HideCursorMode>();
} }
public HleConfiguration CreateHleConfiguration() =>
new(
System.DramSize,
System.Language.Value.ToHLE(),
System.Region.Value.ToHLE(),
Graphics.VSyncMode,
System.EnableDockedMode,
System.EnablePtc,
System.EnableInternetAccess,
System.EnableFsIntegrityChecks
? IntegrityCheckLevel.ErrorOnInvalid
: IntegrityCheckLevel.None,
System.FsGlobalAccessLogMode,
System.MatchSystemTime
? 0
: System.SystemTimeOffset,
System.TimeZone,
System.MemoryManagerMode,
System.IgnoreMissingServices,
Graphics.AspectRatio,
System.AudioVolume,
System.UseHypervisor,
Multiplayer.LanInterfaceId,
Multiplayer.Mode,
Multiplayer.DisableP2p,
Multiplayer.LdnPassphrase,
Instance.Multiplayer.GetLdnServer(),
Instance.Graphics.CustomVSyncInterval,
Instance.Hacks.ShowDirtyHacks ? Instance.Hacks.EnabledHacks : null);
} }
} }

View File

@@ -1,5 +1,5 @@
using Ryujinx.Ava.Utilities.Configuration.System; using Ryujinx.Ava.Systems.Configuration.System;
using Ryujinx.Ava.Utilities.Configuration.UI; using Ryujinx.Ava.Systems.Configuration.UI;
using Ryujinx.Common.Configuration; using Ryujinx.Common.Configuration;
using Ryujinx.Common.Configuration.Hid; using Ryujinx.Common.Configuration.Hid;
using Ryujinx.Common.Configuration.Hid.Keyboard; using Ryujinx.Common.Configuration.Hid.Keyboard;
@@ -9,7 +9,7 @@ using Ryujinx.HLE;
using System; using System;
using System.Linq; using System.Linq;
namespace Ryujinx.Ava.Utilities.Configuration namespace Ryujinx.Ava.Systems.Configuration
{ {
public partial class ConfigurationState public partial class ConfigurationState
{ {
@@ -327,5 +327,5 @@ namespace Ryujinx.Ava.Utilities.Configuration
return GraphicsBackend.OpenGl; return GraphicsBackend.OpenGl;
} }
} }
} }

View File

@@ -1,8 +1,8 @@
using System; using System;
using static Ryujinx.Ava.Utilities.Configuration.ConfigurationState.UISection; using static Ryujinx.Ava.Systems.Configuration.ConfigurationState.UISection;
namespace Ryujinx.Ava.Utilities.Configuration namespace Ryujinx.Ava.Systems.Configuration
{ {
public enum FileTypes public enum FileTypes
{ {

View File

@@ -4,7 +4,7 @@ using Ryujinx.Common.Logging.Targets;
using System; using System;
using System.IO; using System.IO;
namespace Ryujinx.Ava.Utilities.Configuration namespace Ryujinx.Ava.Systems.Configuration
{ {
public static class LoggerModule public static class LoggerModule
{ {

View File

@@ -1,7 +1,7 @@
using Ryujinx.Common.Utilities; using Ryujinx.Common.Utilities;
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
namespace Ryujinx.Ava.Utilities.Configuration.System namespace Ryujinx.Ava.Systems.Configuration.System
{ {
[JsonConverter(typeof(TypedStringEnumConverter<Language>))] [JsonConverter(typeof(TypedStringEnumConverter<Language>))]
public enum Language public enum Language
@@ -25,4 +25,13 @@ namespace Ryujinx.Ava.Utilities.Configuration.System
TraditionalChinese, TraditionalChinese,
BrazilianPortuguese, BrazilianPortuguese,
} }
public static class LanguageEnumHelper
{
public static Language ToUI(this HLE.HOS.SystemState.SystemLanguage hleLanguage)
=> (Language)hleLanguage;
public static HLE.HOS.SystemState.SystemLanguage ToHLE(this Language uiLanguage)
=> (HLE.HOS.SystemState.SystemLanguage)uiLanguage;
}
} }

View File

@@ -0,0 +1,26 @@
using Ryujinx.Common.Utilities;
using System.Text.Json.Serialization;
namespace Ryujinx.Ava.Systems.Configuration.System
{
[JsonConverter(typeof(TypedStringEnumConverter<Region>))]
public enum Region
{
Japan,
USA,
Europe,
Australia,
China,
Korea,
Taiwan,
}
public static class RegionEnumHelper
{
public static Region ToUI(this HLE.HOS.SystemState.RegionCode hleRegion)
=> (Region)hleRegion;
public static HLE.HOS.SystemState.RegionCode ToHLE(this Region uiRegion)
=> (HLE.HOS.SystemState.RegionCode)uiRegion;
}
}

View File

@@ -1,4 +1,4 @@
namespace Ryujinx.Ava.Utilities.Configuration.UI namespace Ryujinx.Ava.Systems.Configuration.UI
{ {
public struct ColumnSort public struct ColumnSort
{ {

View File

@@ -1,7 +1,7 @@
using Ryujinx.Common.Utilities; using Ryujinx.Common.Utilities;
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
namespace Ryujinx.Ava.Utilities.Configuration.UI namespace Ryujinx.Ava.Systems.Configuration.UI
{ {
[JsonConverter(typeof(TypedStringEnumConverter<FocusLostType>))] [JsonConverter(typeof(TypedStringEnumConverter<FocusLostType>))]
public enum FocusLostType public enum FocusLostType

View File

@@ -1,4 +1,4 @@
namespace Ryujinx.Ava.Utilities.Configuration.UI namespace Ryujinx.Ava.Systems.Configuration.UI
{ {
public struct GuiColumns public struct GuiColumns
{ {

View File

@@ -1,4 +1,4 @@
namespace Ryujinx.Ava.Utilities.Configuration.UI namespace Ryujinx.Ava.Systems.Configuration.UI
{ {
public struct ShownFileTypes public struct ShownFileTypes
{ {

View File

@@ -1,7 +1,7 @@
using Ryujinx.Common.Utilities; using Ryujinx.Common.Utilities;
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
namespace Ryujinx.Ava.Utilities.Configuration.UI namespace Ryujinx.Ava.Systems.Configuration.UI
{ {
[JsonConverter(typeof(TypedStringEnumConverter<UpdaterType>))] [JsonConverter(typeof(TypedStringEnumConverter<UpdaterType>))]
public enum UpdaterType public enum UpdaterType

View File

@@ -1,4 +1,4 @@
namespace Ryujinx.Ava.Utilities.Configuration.UI namespace Ryujinx.Ava.Systems.Configuration.UI
{ {
public struct WindowStartup public struct WindowStartup
{ {

View File

@@ -1,5 +1,5 @@
using Gommon; using Gommon;
using Ryujinx.Ava.Utilities.AppLibrary; using Ryujinx.Ava.Systems.AppLibrary;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@@ -7,7 +7,7 @@ using System.Collections.ObjectModel;
using System.Globalization; using System.Globalization;
using System.Linq; using System.Linq;
namespace Ryujinx.Ava.Utilities.PlayReport namespace Ryujinx.Ava.Systems.PlayReport
{ {
/// <summary> /// <summary>
/// The entrypoint for the Play Report analysis system. /// The entrypoint for the Play Report analysis system.

View File

@@ -1,4 +1,4 @@
namespace Ryujinx.Ava.Utilities.PlayReport namespace Ryujinx.Ava.Systems.PlayReport
{ {
/// <summary> /// <summary>
/// The delegate type that powers single value formatters.<br/> /// The delegate type that powers single value formatters.<br/>

View File

@@ -1,8 +1,8 @@
using MsgPack; using MsgPack;
using Ryujinx.Ava.Utilities.AppLibrary; using Ryujinx.Ava.Systems.AppLibrary;
using System.Collections.Generic; using System.Collections.Generic;
namespace Ryujinx.Ava.Utilities.PlayReport namespace Ryujinx.Ava.Systems.PlayReport
{ {
public abstract class MatchedValue<T> public abstract class MatchedValue<T>
{ {

View File

@@ -5,7 +5,7 @@ using System.Buffers.Binary;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
namespace Ryujinx.Ava.Utilities.PlayReport namespace Ryujinx.Ava.Systems.PlayReport
{ {
public partial class PlayReports public partial class PlayReports
{ {

View File

@@ -1,6 +1,6 @@
using System; using System;
namespace Ryujinx.Ava.Utilities.PlayReport namespace Ryujinx.Ava.Systems.PlayReport
{ {
public static partial class PlayReports public static partial class PlayReports
{ {

View File

@@ -1,10 +1,10 @@
using MsgPack; using MsgPack;
using Ryujinx.Ava.Utilities.AppLibrary; using Ryujinx.Ava.Systems.AppLibrary;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
namespace Ryujinx.Ava.Utilities.PlayReport namespace Ryujinx.Ava.Systems.PlayReport
{ {
/// <summary> /// <summary>
/// A mapping of title IDs to value formatter specs. /// A mapping of title IDs to value formatter specs.
@@ -103,7 +103,7 @@ namespace Ryujinx.Ava.Utilities.PlayReport
/// matching a specific set of keys that could exist in a Play Report for the previously specified title IDs. /// matching a specific set of keys that could exist in a Play Report for the previously specified title IDs.
/// <br/><br/> /// <br/><br/>
/// The 'Sparse' multi-value formatters do not require every key to be present. /// The 'Sparse' multi-value formatters do not require every key to be present.
/// If you need this requirement, use <see cref="AddMultiValueFormatter(string[], Ryujinx.Ava.Utilities.PlayReport.MultiValueFormatter)"/>. /// If you need this requirement, use <see cref="AddMultiValueFormatter(string[], MultiValueFormatter)"/>.
/// </summary> /// </summary>
/// <param name="reportKeys">The key names to match.</param> /// <param name="reportKeys">The key names to match.</param>
/// <param name="valueFormatter">The function which can format the values.</param> /// <param name="valueFormatter">The function which can format the values.</param>
@@ -118,7 +118,7 @@ namespace Ryujinx.Ava.Utilities.PlayReport
/// matching a specific set of keys that could exist in a Play Report for the previously specified title IDs. /// matching a specific set of keys that could exist in a Play Report for the previously specified title IDs.
/// <br/><br/> /// <br/><br/>
/// The 'Sparse' multi-value formatters do not require every key to be present. /// The 'Sparse' multi-value formatters do not require every key to be present.
/// If you need this requirement, use <see cref="AddMultiValueFormatter(int, string[], Ryujinx.Ava.Utilities.PlayReport.MultiValueFormatter)"/>. /// If you need this requirement, use <see cref="AddMultiValueFormatter(int, string[], MultiValueFormatter)"/>.
/// </summary> /// </summary>
/// <param name="priority">The resolution priority of this value formatter. Higher resolves sooner.</param> /// <param name="priority">The resolution priority of this value formatter. Higher resolves sooner.</param>
/// <param name="reportKeys">The key names to match.</param> /// <param name="reportKeys">The key names to match.</param>

View File

@@ -3,7 +3,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
namespace Ryujinx.Ava.Utilities.PlayReport namespace Ryujinx.Ava.Systems.PlayReport
{ {
/// <summary> /// <summary>
/// The base input data to a ValueFormatter delegate, /// The base input data to a ValueFormatter delegate,

View File

@@ -7,7 +7,7 @@ using Ryujinx.Ava.UI.Controls;
using Ryujinx.Ava.UI.Helpers; using Ryujinx.Ava.UI.Helpers;
using Ryujinx.Ava.UI.ViewModels; using Ryujinx.Ava.UI.ViewModels;
using Ryujinx.Ava.UI.Windows; using Ryujinx.Ava.UI.Windows;
using Ryujinx.Ava.Utilities.Configuration; using Ryujinx.Ava.Systems.Configuration;
using Ryujinx.Common; using Ryujinx.Common;
using Ryujinx.HLE; using Ryujinx.HLE;
using Ryujinx.HLE.HOS.Applets; using Ryujinx.HLE.HOS.Applets;

View File

@@ -17,12 +17,8 @@
<viewModels:ProfileSelectorDialogViewModel /> <viewModels:ProfileSelectorDialogViewModel />
</Design.DataContext> </Design.DataContext>
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch"> <Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch" RowDefinitions="*,Auto">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Border <Border
CornerRadius="5" CornerRadius="5"
BorderBrush="{DynamicResource AppListHoverBackgroundColor}" BorderBrush="{DynamicResource AppListHoverBackgroundColor}"

View File

@@ -9,17 +9,14 @@ using Ryujinx.Ava.UI.ViewModels;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.HLE.HOS.Services.Account.Acc; using Ryujinx.HLE.HOS.Services.Account.Acc;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Threading.Tasks; using System.Threading.Tasks;
using UserProfile = Ryujinx.Ava.UI.Models.UserProfile; using UserProfile = Ryujinx.Ava.UI.Models.UserProfile;
using UserProfileSft = Ryujinx.HLE.HOS.Services.Account.Acc.UserProfile; using UserProfileSft = Ryujinx.HLE.HOS.Services.Account.Acc.UserProfile;
namespace Ryujinx.Ava.UI.Applet namespace Ryujinx.Ava.UI.Applet
{ {
public partial class ProfileSelectorDialog : UserControl public partial class ProfileSelectorDialog : RyujinxControl<ProfileSelectorDialogViewModel>
{ {
public ProfileSelectorDialogViewModel ViewModel { get; set; }
public ProfileSelectorDialog(ProfileSelectorDialogViewModel viewModel) public ProfileSelectorDialog(ProfileSelectorDialogViewModel viewModel)
{ {
DataContext = ViewModel = viewModel; DataContext = ViewModel = viewModel;

View File

@@ -9,10 +9,10 @@ using Ryujinx.Ava.Common.Locale;
using Ryujinx.Ava.Common.Models; using Ryujinx.Ava.Common.Models;
using Ryujinx.Ava.UI.Helpers; using Ryujinx.Ava.UI.Helpers;
using Ryujinx.Ava.UI.ViewModels; using Ryujinx.Ava.UI.ViewModels;
using Ryujinx.Ava.UI.Views.Misc;
using Ryujinx.Ava.UI.Windows; using Ryujinx.Ava.UI.Windows;
using Ryujinx.Ava.Utilities; using Ryujinx.Ava.Utilities;
using Ryujinx.Ava.Utilities.AppLibrary; using Ryujinx.Ava.Systems.AppLibrary;
using Ryujinx.Ava.Utilities.Compat;
using Ryujinx.Common.Configuration; using Ryujinx.Common.Configuration;
using Ryujinx.Common.Helper; using Ryujinx.Common.Helper;
using Ryujinx.HLE.HOS; using Ryujinx.HLE.HOS;
@@ -26,6 +26,7 @@ namespace Ryujinx.Ava.UI.Controls
{ {
public class ApplicationContextMenu : MenuFlyout public class ApplicationContextMenu : MenuFlyout
{ {
public ApplicationContextMenu() public ApplicationContextMenu()
{ {
InitializeComponent(); InitializeComponent();
@@ -406,7 +407,7 @@ namespace Ryujinx.Ava.UI.Controls
public async void OpenApplicationCompatibility_Click(object sender, RoutedEventArgs args) public async void OpenApplicationCompatibility_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 CompatibilityList.Show(viewModel.SelectedApplication.IdString); await CompatibilityListWindow.Show(viewModel.SelectedApplication.IdString);
} }
public async void OpenApplicationData_Click(object sender, RoutedEventArgs args) public async void OpenApplicationData_Click(object sender, RoutedEventArgs args)

View File

@@ -23,13 +23,12 @@ using UserProfile = Ryujinx.Ava.UI.Models.UserProfile;
namespace Ryujinx.Ava.UI.Controls namespace Ryujinx.Ava.UI.Controls
{ {
public partial class NavigationDialogHost : UserControl public partial class NavigationDialogHost : RyujinxControl<UserProfileViewModel>
{ {
public AccountManager AccountManager { get; } public AccountManager AccountManager { get; }
public ContentManager ContentManager { get; } public ContentManager ContentManager { get; }
public VirtualFileSystem VirtualFileSystem { get; } public VirtualFileSystem VirtualFileSystem { get; }
public HorizonClient HorizonClient { get; } public HorizonClient HorizonClient { get; }
public UserProfileViewModel ViewModel { get; set; }
public NavigationDialogHost() public NavigationDialogHost()
{ {

View File

@@ -0,0 +1,24 @@
using Avalonia.Controls;
using Gommon;
using Ryujinx.Ava.UI.ViewModels;
using System;
namespace Ryujinx.Ava.UI.Controls
{
public class RyujinxControl<TViewModel> : UserControl where TViewModel : BaseModel
{
public TViewModel ViewModel
{
get
{
if (DataContext is not TViewModel viewModel)
throw new InvalidOperationException(
$"Underlying DataContext is not of type {typeof(TViewModel).AsPrettyString()}; " +
$"Actual type is {DataContext?.GetType().AsPrettyString()}");
return viewModel;
}
set => DataContext = value;
}
}
}

View File

@@ -1,5 +1,5 @@
using Avalonia.Interactivity; using Avalonia.Interactivity;
using Ryujinx.Ava.Utilities.AppLibrary; using Ryujinx.Ava.Systems.AppLibrary;
namespace Ryujinx.Ava.UI.Helpers namespace Ryujinx.Ava.UI.Helpers
{ {

View File

@@ -4,6 +4,7 @@ using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Input; using Avalonia.Input;
using Avalonia.Layout; using Avalonia.Layout;
using Avalonia.Media; using Avalonia.Media;
using Avalonia.Styling;
using Avalonia.Threading; using Avalonia.Threading;
using FluentAvalonia.Core; using FluentAvalonia.Core;
using FluentAvalonia.UI.Controls; using FluentAvalonia.UI.Controls;
@@ -21,6 +22,23 @@ namespace Ryujinx.Ava.UI.Helpers
private static bool _isChoiceDialogOpen; private static bool _isChoiceDialogOpen;
private static ContentDialogOverlayWindow _contentDialogOverlayWindow; private static ContentDialogOverlayWindow _contentDialogOverlayWindow;
public static ContentDialog ApplyStyles(
this ContentDialog contentDialog,
double closeButtonWidth = 80,
HorizontalAlignment buttonSpaceAlignment = HorizontalAlignment.Right)
{
Style closeButton = new(x => x.Name("CloseButton"));
closeButton.Setters.Add(new Setter(Layoutable.WidthProperty, closeButtonWidth));
Style closeButtonParent = new(x => x.Name("CommandSpace"));
closeButtonParent.Setters.Add(new Setter(Layoutable.HorizontalAlignmentProperty, buttonSpaceAlignment));
contentDialog.Styles.Add(closeButton);
contentDialog.Styles.Add(closeButtonParent);
return contentDialog;
}
private async static Task<UserResult> ShowContentDialog( private async static Task<UserResult> ShowContentDialog(
string title, string title,
object content, object content,
@@ -40,19 +58,19 @@ namespace Ryujinx.Ava.UI.Helpers
SecondaryButtonText = secondaryButton, SecondaryButtonText = secondaryButton,
CloseButtonText = closeButton, CloseButtonText = closeButton,
Content = content, Content = content,
PrimaryButtonCommand = MiniCommand.Create(() => PrimaryButtonCommand = Commands.Create(() =>
{ {
result = primaryButtonResult; result = primaryButtonResult;
}) })
}; };
contentDialog.SecondaryButtonCommand = MiniCommand.Create(() => contentDialog.SecondaryButtonCommand = Commands.Create(() =>
{ {
result = UserResult.No; result = UserResult.No;
contentDialog.PrimaryButtonClick -= deferCloseAction; contentDialog.PrimaryButtonClick -= deferCloseAction;
}); });
contentDialog.CloseButtonCommand = MiniCommand.Create(() => contentDialog.CloseButtonCommand = Commands.Create(() =>
{ {
result = UserResult.Cancel; result = UserResult.Cancel;
contentDialog.PrimaryButtonClick -= deferCloseAction; contentDialog.PrimaryButtonClick -= deferCloseAction;

View File

@@ -2,7 +2,7 @@ using Avalonia.Data.Converters;
using Avalonia.Markup.Xaml; using Avalonia.Markup.Xaml;
using Gommon; using Gommon;
using Ryujinx.Ava.Common.Locale; using Ryujinx.Ava.Common.Locale;
using Ryujinx.Ava.Utilities.AppLibrary; using Ryujinx.Ava.Systems.AppLibrary;
using System; using System;
using System.Globalization; using System.Globalization;
using System.Text; using System.Text;

View File

@@ -1,7 +1,7 @@
using Avalonia.Logging; using Avalonia.Logging;
using Avalonia.Utilities; using Avalonia.Utilities;
using Gommon; using Gommon;
using Ryujinx.Ava.Utilities.Configuration; using Ryujinx.Ava.Systems.Configuration;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using System; using System;
using System.Text; using System.Text;

View File

@@ -1,72 +0,0 @@
using System;
using System.Threading.Tasks;
using System.Windows.Input;
namespace Ryujinx.Ava.UI.Helpers
{
public sealed class MiniCommand<T> : MiniCommand, ICommand
{
private readonly Action<T> _callback;
private bool _busy;
private readonly Func<T, Task> _asyncCallback;
public MiniCommand(Action<T> callback)
{
_callback = callback;
}
public MiniCommand(Func<T, Task> callback)
{
_asyncCallback = callback;
}
private bool Busy
{
get => _busy;
set
{
_busy = value;
CanExecuteChanged?.Invoke(this, EventArgs.Empty);
}
}
public override event EventHandler CanExecuteChanged;
public override bool CanExecute(object parameter) => !_busy;
public override async void Execute(object parameter)
{
if (Busy)
{
return;
}
try
{
Busy = true;
if (_callback != null)
{
_callback((T)parameter);
}
else
{
await _asyncCallback((T)parameter);
}
}
finally
{
Busy = false;
}
}
}
public abstract class MiniCommand : ICommand
{
public static MiniCommand Create(Action callback) => new MiniCommand<object>(_ => callback());
public static MiniCommand Create<TArg>(Action<TArg> callback) => new MiniCommand<TArg>(callback);
public static MiniCommand CreateFromTask(Func<Task> callback) => new MiniCommand<object>(_ => callback());
public static MiniCommand CreateFromTask<TArg>(Func<TArg, Task> callback) => new MiniCommand<TArg>(callback);
public abstract bool CanExecute(object parameter);
public abstract void Execute(object parameter);
public abstract event EventHandler CanExecuteChanged;
}
}

View File

@@ -1,4 +1,4 @@
using Ryujinx.Ava.Utilities.AppLibrary; using Ryujinx.Ava.Systems.AppLibrary;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;

View File

@@ -1,4 +1,4 @@
using Ryujinx.Ava.Utilities.AppLibrary; using Ryujinx.Ava.Systems.AppLibrary;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;

View File

@@ -0,0 +1,260 @@
using Ryujinx.Ava.UI.ViewModels;
using Ryujinx.Ava.UI.ViewModels.Input;
using Ryujinx.Input;
using System;
using System.Threading;
using System.Threading.Tasks;
namespace Ryujinx.Ava.UI.Models.Input
{
public class StickVisualizer : BaseModel, IDisposable
{
public const int DrawStickPollRate = 50; // Milliseconds per poll.
public const int DrawStickCircumference = 5;
public const float DrawStickScaleFactor = DrawStickCanvasCenter;
public const int DrawStickCanvasSize = 100;
public const int DrawStickBorderSize = DrawStickCanvasSize + 5;
public const float DrawStickCanvasCenter = (DrawStickCanvasSize - DrawStickCircumference) / 2;
public const float MaxVectorLength = DrawStickCanvasSize / 2;
public CancellationTokenSource PollTokenSource;
public CancellationToken PollToken;
private static float _vectorLength;
private static float _vectorMultiplier;
private bool disposedValue;
private DeviceType _type;
public DeviceType Type
{
get => _type;
set
{
_type = value;
OnPropertyChanged();
}
}
private GamepadInputConfig _gamepadConfig;
public GamepadInputConfig GamepadConfig
{
get => _gamepadConfig;
set
{
_gamepadConfig = value;
OnPropertyChanged();
}
}
private KeyboardInputConfig _keyboardConfig;
public KeyboardInputConfig KeyboardConfig
{
get => _keyboardConfig;
set
{
_keyboardConfig = value;
OnPropertyChanged();
}
}
private (float, float) _uiStickLeft;
public (float, float) UiStickLeft
{
get => (_uiStickLeft.Item1 * DrawStickScaleFactor, _uiStickLeft.Item2 * DrawStickScaleFactor);
set
{
_uiStickLeft = value;
OnPropertyChanged();
OnPropertyChanged(nameof(UiStickRightX));
OnPropertyChanged(nameof(UiStickRightY));
OnPropertyChanged(nameof(UiDeadzoneRight));
}
}
private (float, float) _uiStickRight;
public (float, float) UiStickRight
{
get => (_uiStickRight.Item1 * DrawStickScaleFactor, _uiStickRight.Item2 * DrawStickScaleFactor);
set
{
_uiStickRight = value;
OnPropertyChanged();
OnPropertyChanged(nameof(UiStickLeftX));
OnPropertyChanged(nameof(UiStickLeftY));
OnPropertyChanged(nameof(UiDeadzoneLeft));
}
}
public float UiStickLeftX => ClampVector(UiStickLeft).Item1;
public float UiStickLeftY => ClampVector(UiStickLeft).Item2;
public float UiStickRightX => ClampVector(UiStickRight).Item1;
public float UiStickRightY => ClampVector(UiStickRight).Item2;
public int UiStickCircumference => DrawStickCircumference;
public int UiCanvasSize => DrawStickCanvasSize;
public int UiStickBorderSize => DrawStickBorderSize;
public float? UiDeadzoneLeft => _gamepadConfig?.DeadzoneLeft * DrawStickCanvasSize - DrawStickCircumference;
public float? UiDeadzoneRight => _gamepadConfig?.DeadzoneRight * DrawStickCanvasSize - DrawStickCircumference;
private InputViewModel Parent;
public StickVisualizer(InputViewModel parent)
{
Parent = parent;
PollTokenSource = new CancellationTokenSource();
PollToken = PollTokenSource.Token;
Task.Run(Initialize, PollToken);
}
public void UpdateConfig(object config)
{
if (config is ControllerInputViewModel padConfig)
{
GamepadConfig = padConfig.Config;
Type = DeviceType.Controller;
return;
}
else if (config is KeyboardInputViewModel keyConfig)
{
KeyboardConfig = keyConfig.Config;
Type = DeviceType.Keyboard;
return;
}
Type = DeviceType.None;
}
public async Task Initialize()
{
(float, float) leftBuffer;
(float, float) rightBuffer;
while (!PollToken.IsCancellationRequested)
{
leftBuffer = (0f, 0f);
rightBuffer = (0f, 0f);
switch (Type)
{
case DeviceType.Keyboard:
IKeyboard keyboard = (IKeyboard)Parent.AvaloniaKeyboardDriver.GetGamepad("0");
if (keyboard != null)
{
KeyboardStateSnapshot snapshot = keyboard.GetKeyboardStateSnapshot();
if (snapshot.IsPressed((Key)KeyboardConfig.LeftStickRight))
{
leftBuffer.Item1 += 1;
}
if (snapshot.IsPressed((Key)KeyboardConfig.LeftStickLeft))
{
leftBuffer.Item1 -= 1;
}
if (snapshot.IsPressed((Key)KeyboardConfig.LeftStickUp))
{
leftBuffer.Item2 += 1;
}
if (snapshot.IsPressed((Key)KeyboardConfig.LeftStickDown))
{
leftBuffer.Item2 -= 1;
}
if (snapshot.IsPressed((Key)KeyboardConfig.RightStickRight))
{
rightBuffer.Item1 += 1;
}
if (snapshot.IsPressed((Key)KeyboardConfig.RightStickLeft))
{
rightBuffer.Item1 -= 1;
}
if (snapshot.IsPressed((Key)KeyboardConfig.RightStickUp))
{
rightBuffer.Item2 += 1;
}
if (snapshot.IsPressed((Key)KeyboardConfig.RightStickDown))
{
rightBuffer.Item2 -= 1;
}
UiStickLeft = leftBuffer;
UiStickRight = rightBuffer;
}
break;
case DeviceType.Controller:
IGamepad controller = Parent.SelectedGamepad;
if (controller != null)
{
leftBuffer = controller.GetStick((StickInputId)GamepadConfig.LeftJoystick);
rightBuffer = controller.GetStick((StickInputId)GamepadConfig.RightJoystick);
}
break;
case DeviceType.None:
break;
default:
throw new ArgumentException($"Unable to poll device type \"{Type}\"");
}
UiStickLeft = leftBuffer;
UiStickRight = rightBuffer;
await Task.Delay(DrawStickPollRate, PollToken);
}
PollTokenSource.Dispose();
}
public static (float, float) ClampVector((float, float) vect)
{
_vectorMultiplier = 1;
_vectorLength = MathF.Sqrt((vect.Item1 * vect.Item1) + (vect.Item2 * vect.Item2));
if (_vectorLength > MaxVectorLength)
{
_vectorMultiplier = MaxVectorLength / _vectorLength;
}
vect.Item1 = vect.Item1 * _vectorMultiplier + DrawStickCanvasCenter;
vect.Item2 = vect.Item2 * _vectorMultiplier + DrawStickCanvasCenter;
return vect;
}
protected virtual void Dispose(bool disposing)
{
if (!disposedValue)
{
if (disposing)
{
PollTokenSource.Cancel();
}
KeyboardConfig = null;
GamepadConfig = null;
Parent = null;
disposedValue = true;
}
}
public void Dispose()
{
Dispose(disposing: true);
GC.SuppressFinalize(this);
}
}
}

View File

@@ -3,7 +3,7 @@ using LibHac.Fs;
using LibHac.Ncm; using LibHac.Ncm;
using Ryujinx.Ava.UI.ViewModels; using Ryujinx.Ava.UI.ViewModels;
using Ryujinx.Ava.Utilities; using Ryujinx.Ava.Utilities;
using Ryujinx.Ava.Utilities.AppLibrary; using Ryujinx.Ava.Systems.AppLibrary;
using Ryujinx.HLE.FileSystem; using Ryujinx.HLE.FileSystem;
using System.IO; using System.IO;
using System.Linq; using System.Linq;

View File

@@ -1,7 +1,7 @@
using Avalonia; using Avalonia;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Platform; using Avalonia.Platform;
using Ryujinx.Ava.Utilities.Configuration; using Ryujinx.Ava.Systems.Configuration;
using Ryujinx.Common.Configuration; using Ryujinx.Common.Configuration;
using Ryujinx.Common.Helper; using Ryujinx.Common.Helper;
using SPB.Graphics; using SPB.Graphics;

View File

@@ -1,5 +1,5 @@
using OpenTK.Graphics.OpenGL; using OpenTK.Graphics.OpenGL;
using Ryujinx.Ava.Utilities.Configuration; using Ryujinx.Ava.Systems.Configuration;
using Ryujinx.Common.Configuration; using Ryujinx.Common.Configuration;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.Graphics.GAL; using Ryujinx.Graphics.GAL;

View File

@@ -1,10 +1,8 @@
using Avalonia; using Avalonia;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Media; using Avalonia.Media;
using Ryujinx.Ava.Utilities.Configuration; using Ryujinx.Ava.Systems.Configuration;
using Ryujinx.Common;
using Ryujinx.Common.Configuration; using Ryujinx.Common.Configuration;
using Ryujinx.Common.Logging;
using System; using System;
namespace Ryujinx.Ava.UI.Renderer namespace Ryujinx.Ava.UI.Renderer
@@ -38,32 +36,6 @@ namespace Ryujinx.Ava.UI.Renderer
EmbeddedWindowOpenGL => GraphicsBackend.OpenGl, EmbeddedWindowOpenGL => GraphicsBackend.OpenGl,
_ => throw new NotImplementedException() _ => throw new NotImplementedException()
}; };
public RendererHost(string titleId)
{
Focusable = true;
FlowDirection = FlowDirection.LeftToRight;
EmbeddedWindow =
#pragma warning disable CS8524
ConfigurationState.Instance.Graphics.GraphicsBackend.Value switch
#pragma warning restore CS8524
{
GraphicsBackend.OpenGl => new EmbeddedWindowOpenGL(),
GraphicsBackend.Vulkan => new EmbeddedWindowVulkan(),
};
string backendText = EmbeddedWindow switch
{
EmbeddedWindowVulkan => "Vulkan",
EmbeddedWindowOpenGL => "OpenGL",
_ => throw new NotImplementedException()
};
Logger.Info?.PrintMsg(LogClass.Gpu, $"Backend ({ConfigurationState.Instance.Graphics.GraphicsBackend.Value}): {backendText}");
Initialize();
}
private void Initialize() private void Initialize()

View File

@@ -5,7 +5,7 @@ using CommunityToolkit.Mvvm.ComponentModel;
using Gommon; using Gommon;
using Ryujinx.Ava.Common; using Ryujinx.Ava.Common;
using Ryujinx.Ava.Common.Locale; using Ryujinx.Ava.Common.Locale;
using Ryujinx.Ava.Utilities.Configuration; using Ryujinx.Ava.Systems.Configuration;
using System; using System;
namespace Ryujinx.Ava.UI.ViewModels namespace Ryujinx.Ava.UI.ViewModels

View File

@@ -1,4 +1,4 @@
using Ryujinx.Ava.Utilities.AppLibrary; using Ryujinx.Ava.Systems.AppLibrary;
using System; using System;
namespace Ryujinx.Ava.UI.ViewModels namespace Ryujinx.Ava.UI.ViewModels

View File

@@ -1,7 +1,7 @@
using Gommon; using Gommon;
using Ryujinx.Ava.Common.Locale; using Ryujinx.Ava.Common.Locale;
using Ryujinx.Ava.Utilities.AppLibrary; using Ryujinx.Ava.Systems.AppLibrary;
using Ryujinx.Ava.Utilities.PlayReport; using Ryujinx.Ava.Systems.PlayReport;
namespace Ryujinx.Ava.UI.ViewModels namespace Ryujinx.Ava.UI.ViewModels
{ {

View File

@@ -1,10 +1,11 @@
using Gommon; using Gommon;
using Ryujinx.Ava.UI.ViewModels; using Ryujinx.Ava.Systems;
using Ryujinx.Ava.Utilities.AppLibrary; using Ryujinx.Ava.Systems.AppLibrary;
using Ryujinx.Ava.UI.Windows;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
namespace Ryujinx.Ava.Utilities.Compat namespace Ryujinx.Ava.UI.ViewModels
{ {
public class CompatibilityViewModel : BaseModel public class CompatibilityViewModel : BaseModel
{ {

View File

@@ -1,6 +1,6 @@
using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.ComponentModel;
using Ryujinx.Ava.Common.Models; using Ryujinx.Ava.Common.Models;
using Ryujinx.Ava.Utilities.AppLibrary; using Ryujinx.Ava.Systems.AppLibrary;
using System.Linq; using System.Linq;
namespace Ryujinx.Ava.UI.ViewModels namespace Ryujinx.Ava.UI.ViewModels

View File

@@ -7,7 +7,7 @@ using FluentAvalonia.UI.Controls;
using Ryujinx.Ava.Common.Locale; using Ryujinx.Ava.Common.Locale;
using Ryujinx.Ava.Common.Models; using Ryujinx.Ava.Common.Models;
using Ryujinx.Ava.UI.Helpers; using Ryujinx.Ava.UI.Helpers;
using Ryujinx.Ava.Utilities.AppLibrary; using Ryujinx.Ava.Systems.AppLibrary;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.IO; using System.IO;

View File

@@ -1,5 +1,9 @@
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.Input;
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.Common.Utilities;
@@ -10,8 +14,30 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
{ {
public partial class ControllerInputViewModel : BaseModel public partial class ControllerInputViewModel : BaseModel
{ {
[ObservableProperty] private GamepadInputConfig _config; private GamepadInputConfig _config;
public GamepadInputConfig Config
{
get => _config;
set
{
_config = value;
OnPropertyChanged();
}
}
private StickVisualizer _visualizer;
public StickVisualizer Visualizer
{
get => _visualizer;
set
{
_visualizer = value;
OnPropertyChanged();
}
}
private bool _isLeft; private bool _isLeft;
public bool IsLeft public bool IsLeft
{ {
@@ -37,14 +63,15 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
} }
public bool HasSides => IsLeft ^ IsRight; public bool HasSides => IsLeft ^ IsRight;
[ObservableProperty] private SvgImage _image; [ObservableProperty] private SvgImage _image;
public InputViewModel ParentModel { get; } public InputViewModel ParentModel { get; }
public ControllerInputViewModel(InputViewModel model, GamepadInputConfig config) public ControllerInputViewModel(InputViewModel model, GamepadInputConfig config, StickVisualizer visualizer)
{ {
ParentModel = model; ParentModel = model;
Visualizer = visualizer;
model.NotifyChangesEvent += OnParentModelChanged; model.NotifyChangesEvent += OnParentModelChanged;
OnParentModelChanged(); OnParentModelChanged();
config.PropertyChanged += (_, args) => config.PropertyChanged += (_, args) =>

View File

@@ -10,7 +10,7 @@ using Ryujinx.Ava.UI.Helpers;
using Ryujinx.Ava.UI.Models; using Ryujinx.Ava.UI.Models;
using Ryujinx.Ava.UI.Models.Input; using Ryujinx.Ava.UI.Models.Input;
using Ryujinx.Ava.UI.Windows; using Ryujinx.Ava.UI.Windows;
using Ryujinx.Ava.Utilities.Configuration; using Ryujinx.Ava.Systems.Configuration;
using Ryujinx.Common; using Ryujinx.Common;
using Ryujinx.Common.Configuration; using Ryujinx.Common.Configuration;
using Ryujinx.Common.Configuration.Hid; using Ryujinx.Common.Configuration.Hid;
@@ -49,7 +49,7 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
private int _controller; private int _controller;
private string _controllerImage; private string _controllerImage;
private int _device; private int _device;
[ObservableProperty] private object _configViewModel; private object _configViewModel;
[ObservableProperty] private string _profileName; [ObservableProperty] private string _profileName;
private bool _isLoaded; private bool _isLoaded;
@@ -74,6 +74,7 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
OnPropertiesChanged(nameof(HasLed), nameof(CanClearLed)); OnPropertiesChanged(nameof(HasLed), nameof(CanClearLed));
} }
} }
public StickVisualizer VisualStick { get; private set; }
public ObservableCollection<PlayerModel> PlayerIndexes { get; set; } public ObservableCollection<PlayerModel> PlayerIndexes { get; set; }
public ObservableCollection<(DeviceType Type, string Id, string Name)> Devices { get; set; } public ObservableCollection<(DeviceType Type, string Id, string Name)> Devices { get; set; }
@@ -94,6 +95,19 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
public bool IsModified { get; set; } public bool IsModified { get; set; }
public event Action NotifyChangesEvent; public event Action NotifyChangesEvent;
public object ConfigViewModel
{
get => _configViewModel;
set
{
_configViewModel = value;
VisualStick.UpdateConfig(value);
OnPropertyChanged();
}
}
public PlayerIndex PlayerIdChoose public PlayerIndex PlayerIdChoose
{ {
get => _playerIdChoose; get => _playerIdChoose;
@@ -269,6 +283,7 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
Devices = []; Devices = [];
ProfilesList = []; ProfilesList = [];
DeviceList = []; DeviceList = [];
VisualStick = new StickVisualizer(this);
ControllerImage = ProControllerResource; ControllerImage = ProControllerResource;
@@ -289,12 +304,12 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
if (Config is StandardKeyboardInputConfig keyboardInputConfig) if (Config is StandardKeyboardInputConfig keyboardInputConfig)
{ {
ConfigViewModel = new KeyboardInputViewModel(this, new KeyboardInputConfig(keyboardInputConfig)); ConfigViewModel = new KeyboardInputViewModel(this, new KeyboardInputConfig(keyboardInputConfig), VisualStick);
} }
if (Config is StandardControllerInputConfig controllerInputConfig) if (Config is StandardControllerInputConfig controllerInputConfig)
{ {
ConfigViewModel = new ControllerInputViewModel(this, new GamepadInputConfig(controllerInputConfig)); ConfigViewModel = new ControllerInputViewModel(this, new GamepadInputConfig(controllerInputConfig), VisualStick);
} }
} }
@@ -893,6 +908,8 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
_mainWindow.ViewModel.AppHost?.NpadManager.UnblockInputUpdates(); _mainWindow.ViewModel.AppHost?.NpadManager.UnblockInputUpdates();
VisualStick.Dispose();
SelectedGamepad?.Dispose(); SelectedGamepad?.Dispose();
AvaloniaKeyboardDriver.Dispose(); AvaloniaKeyboardDriver.Dispose();

View File

@@ -6,7 +6,29 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
{ {
public partial class KeyboardInputViewModel : BaseModel public partial class KeyboardInputViewModel : BaseModel
{ {
[ObservableProperty] private KeyboardInputConfig _config; private KeyboardInputConfig _config;
public KeyboardInputConfig Config
{
get => _config;
set
{
_config = value;
OnPropertyChanged();
}
}
private StickVisualizer _visualizer;
public StickVisualizer Visualizer
{
get => _visualizer;
set
{
_visualizer = value;
OnPropertyChanged();
}
}
private bool _isLeft; private bool _isLeft;
public bool IsLeft public bool IsLeft
@@ -38,9 +60,10 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
public readonly InputViewModel ParentModel; public readonly InputViewModel ParentModel;
public KeyboardInputViewModel(InputViewModel model, KeyboardInputConfig config) public KeyboardInputViewModel(InputViewModel model, KeyboardInputConfig config, StickVisualizer visualizer)
{ {
ParentModel = model; ParentModel = model;
Visualizer = visualizer;
model.NotifyChangesEvent += OnParentModelChanged; model.NotifyChangesEvent += OnParentModelChanged;
OnParentModelChanged(); OnParentModelChanged();
Config = config; Config = config;

View File

@@ -3,7 +3,7 @@ using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input; using CommunityToolkit.Mvvm.Input;
using Humanizer; using Humanizer;
using Ryujinx.Ava.UI.Helpers; using Ryujinx.Ava.UI.Helpers;
using Ryujinx.Ava.Utilities.Configuration; using Ryujinx.Ava.Systems.Configuration;
using System.Globalization; using System.Globalization;
namespace Ryujinx.Ava.UI.ViewModels.Input namespace Ryujinx.Ava.UI.ViewModels.Input

View File

@@ -23,8 +23,8 @@ using Ryujinx.Ava.UI.Models;
using Ryujinx.Ava.UI.Models.Generic; using Ryujinx.Ava.UI.Models.Generic;
using Ryujinx.Ava.UI.Renderer; using Ryujinx.Ava.UI.Renderer;
using Ryujinx.Ava.UI.Windows; using Ryujinx.Ava.UI.Windows;
using Ryujinx.Ava.Utilities.AppLibrary; using Ryujinx.Ava.Systems.AppLibrary;
using Ryujinx.Ava.Utilities.Configuration; using Ryujinx.Ava.Systems.Configuration;
using Ryujinx.Common; using Ryujinx.Common;
using Ryujinx.Common.Configuration; using Ryujinx.Common.Configuration;
using Ryujinx.Common.Helper; using Ryujinx.Common.Helper;

View File

@@ -7,7 +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.Ava.Systems.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;

View File

@@ -1,6 +1,6 @@
using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.ComponentModel;
using Gommon; using Gommon;
using Ryujinx.Ava.Utilities.Configuration; using Ryujinx.Ava.Systems.Configuration;
namespace Ryujinx.Ava.UI.ViewModels namespace Ryujinx.Ava.UI.ViewModels
{ {

View File

@@ -12,9 +12,9 @@ using Ryujinx.Ava.Common.Locale;
using Ryujinx.Ava.UI.Helpers; using Ryujinx.Ava.UI.Helpers;
using Ryujinx.Ava.UI.Models.Input; using Ryujinx.Ava.UI.Models.Input;
using Ryujinx.Ava.UI.Windows; using Ryujinx.Ava.UI.Windows;
using Ryujinx.Ava.Utilities.Configuration; using Ryujinx.Ava.Systems.Configuration;
using Ryujinx.Ava.Utilities.Configuration.System; using Ryujinx.Ava.Systems.Configuration.System;
using Ryujinx.Ava.Utilities.Configuration.UI; using Ryujinx.Ava.Systems.Configuration.UI;
using Ryujinx.Common.Configuration; using Ryujinx.Common.Configuration;
using Ryujinx.Common.Configuration.Multiplayer; using Ryujinx.Common.Configuration.Multiplayer;
using Ryujinx.Common.GraphicsDriver; using Ryujinx.Common.GraphicsDriver;

View File

@@ -6,7 +6,7 @@ using FluentAvalonia.UI.Controls;
using Ryujinx.Ava.Common.Locale; using Ryujinx.Ava.Common.Locale;
using Ryujinx.Ava.Common.Models; using Ryujinx.Ava.Common.Models;
using Ryujinx.Ava.UI.Helpers; using Ryujinx.Ava.UI.Helpers;
using Ryujinx.Ava.Utilities.AppLibrary; using Ryujinx.Ava.Systems.AppLibrary;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;

View File

@@ -21,7 +21,7 @@ using Image = SkiaSharp.SKImage;
namespace Ryujinx.Ava.UI.ViewModels namespace Ryujinx.Ava.UI.ViewModels
{ {
internal partial class UserFirmwareAvatarSelectorViewModel : BaseModel public partial class UserFirmwareAvatarSelectorViewModel : BaseModel
{ {
private static readonly Dictionary<string, byte[]> _avatarStore = new(); private static readonly Dictionary<string, byte[]> _avatarStore = new();

View File

@@ -2,7 +2,7 @@ using CommunityToolkit.Mvvm.ComponentModel;
namespace Ryujinx.Ava.UI.ViewModels namespace Ryujinx.Ava.UI.ViewModels
{ {
internal partial class UserProfileImageSelectorViewModel : BaseModel public partial class UserProfileImageSelectorViewModel : BaseModel
{ {
[ObservableProperty] private bool _firmwareFound; [ObservableProperty] private bool _firmwareFound;
} }

View File

@@ -6,7 +6,7 @@ using Ryujinx.Ava.Common;
using Ryujinx.Ava.Common.Locale; using Ryujinx.Ava.Common.Locale;
using Ryujinx.Ava.Common.Models; using Ryujinx.Ava.Common.Models;
using Ryujinx.Ava.UI.Helpers; using Ryujinx.Ava.UI.Helpers;
using Ryujinx.Ava.Utilities.AppLibrary; using Ryujinx.Ava.Systems.AppLibrary;
using Ryujinx.Common.Utilities; using Ryujinx.Common.Utilities;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;

View File

@@ -34,12 +34,7 @@
<!-- Button / JoyStick Settings --> <!-- Button / JoyStick Settings -->
<Grid <Grid
Name="SettingButtons" Name="SettingButtons"
MinHeight="450"> MinHeight="450" ColumnDefinitions="Auto,*,Auto">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<!-- Left Controls --> <!-- Left Controls -->
<StackPanel <StackPanel
Orientation="Vertical" Orientation="Vertical"
@@ -54,15 +49,7 @@
CornerRadius="5"> CornerRadius="5">
<Grid <Grid
Margin="10" Margin="10"
HorizontalAlignment="Stretch"> HorizontalAlignment="Stretch" ColumnDefinitions="*,*" RowDefinitions="*,*">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<StackPanel <StackPanel
Grid.Column="0" Grid.Column="0"
Grid.Row="0" Grid.Row="0"
@@ -316,17 +303,99 @@
HorizontalAlignment="Stretch" HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"> VerticalAlignment="Stretch">
<!-- Controller Picture --> <!-- Controller Picture -->
<Image
Margin="0,10"
MaxHeight="300"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Source="{Binding Image}" />
<Border <Border
BorderBrush="{DynamicResource ThemeControlBorderColor}" BorderBrush="{DynamicResource ThemeControlBorderColor}"
BorderThickness="1" BorderThickness="1"
CornerRadius="5" CornerRadius="5"
Margin="0,0, 0, 5"
MinHeight="90"> MinHeight="90">
<StackPanel Orientation="Vertical">
<Image
Margin="5,10"
MaxHeight="300"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Source="{Binding Image}" />
<StackPanel
Margin="10"
Orientation="Horizontal"
Spacing="20"
HorizontalAlignment="Center">
<Border
BorderBrush="Transparent"
Height="{Binding Visualizer.UiStickBorderSize}"
Width="{Binding Visualizer.UiStickBorderSize}"
IsVisible="{Binding IsLeft}">
<Canvas
Background="{DynamicResource ThemeBackgroundColor}"
Height="{Binding Visualizer.UiCanvasSize}"
Width="{Binding Visualizer.UiCanvasSize}">
<Grid
Height="{Binding Visualizer.UiCanvasSize}"
Width="{Binding Visualizer.UiCanvasSize}"
Background="{DynamicResource ThemeBackgroundColor}">
<Ellipse
HorizontalAlignment="Center"
Stroke="{DynamicResource ThemeControlBorderColor}"
StrokeThickness="1"
Width="{Binding Visualizer.UiCanvasSize}"
Height="{Binding Visualizer.UiCanvasSize}" />
<Ellipse
HorizontalAlignment="Center"
Fill="Black"
Opacity="100"
Height="{Binding Visualizer.UiDeadzoneLeft}"
Width="{Binding Visualizer.UiDeadzoneLeft}" />
</Grid>
<Ellipse
Fill="{DynamicResource Warning}"
Width="{Binding Visualizer.UiStickCircumference}"
Height="{Binding Visualizer.UiStickCircumference}"
Canvas.Bottom="{Binding Visualizer.UiStickLeftY}"
Canvas.Left="{Binding Visualizer.UiStickLeftX}" />
</Canvas>
</Border>
<Border
BorderBrush="Transparent"
Height="{Binding Visualizer.UiStickBorderSize}"
Width="{Binding Visualizer.UiStickBorderSize}"
IsVisible="{Binding IsRight}">
<Canvas
Background="{DynamicResource ThemeBackgroundColor}"
Height="{Binding Visualizer.UiCanvasSize}"
Width="{Binding Visualizer.UiCanvasSize}">
<Grid
Height="{Binding Visualizer.UiCanvasSize}"
Width="{Binding Visualizer.UiCanvasSize}"
Background="{DynamicResource ThemeBackgroundColor}">
<Ellipse
HorizontalAlignment="Center"
Stroke="{DynamicResource ThemeControlBorderColor}"
StrokeThickness="1"
Width="{Binding Visualizer.UiCanvasSize}"
Height="{Binding Visualizer.UiCanvasSize}" />
<Ellipse
HorizontalAlignment="Center"
Fill="Black"
Opacity="100"
Height="{Binding Visualizer.UiDeadzoneRight}"
Width="{Binding Visualizer.UiDeadzoneRight}" />
</Grid>
<Ellipse
Fill="{DynamicResource Warning}"
Width="{Binding Visualizer.UiStickCircumference}"
Height="{Binding Visualizer.UiStickCircumference}"
Canvas.Bottom="{Binding Visualizer.UiStickRightY}"
Canvas.Left="{Binding Visualizer.UiStickRightX}" />
</Canvas>
</Border>
</StackPanel>
</StackPanel>
</Border>
<Border
BorderBrush="{DynamicResource ThemeControlBorderColor}"
BorderThickness="1"
CornerRadius="5">
<StackPanel <StackPanel
Margin="8" Margin="8"
Orientation="Vertical"> Orientation="Vertical">
@@ -345,8 +414,8 @@
Minimum="0" Minimum="0"
Value="{Binding Config.TriggerThreshold, Mode=TwoWay}" /> Value="{Binding Config.TriggerThreshold, Mode=TwoWay}" />
<TextBlock <TextBlock
Width="25" Width="25"
Text="{Binding Config.TriggerThreshold, StringFormat=\{0:0.00\}}" /> Text="{Binding Config.TriggerThreshold, StringFormat=\{0:0.00\}}" />
</StackPanel> </StackPanel>
<StackPanel <StackPanel
Orientation="Vertical" Orientation="Vertical"
@@ -428,7 +497,7 @@
</Border> </Border>
<!-- Motion, Rumble, LED --> <!-- Motion, Rumble, LED -->
<StackPanel <StackPanel
Margin="0,10,0,0" Margin="0,5,0,0"
Spacing="5" Spacing="5"
Orientation="Vertical" Orientation="Vertical"
VerticalAlignment="Bottom"> VerticalAlignment="Bottom">
@@ -438,11 +507,7 @@
CornerRadius="5" CornerRadius="5"
VerticalAlignment="Bottom" VerticalAlignment="Bottom"
HorizontalAlignment="Stretch"> HorizontalAlignment="Stretch">
<Grid> <Grid ColumnDefinitions="*,Auto">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<CheckBox <CheckBox
Margin="10" Margin="10"
MinWidth="0" MinWidth="0"
@@ -464,11 +529,7 @@
CornerRadius="5" CornerRadius="5"
HorizontalAlignment="Stretch" HorizontalAlignment="Stretch"
Margin="0,-1,0,0"> Margin="0,-1,0,0">
<Grid> <Grid ColumnDefinitions="*,Auto">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<CheckBox <CheckBox
Margin="10" Margin="10"
MinWidth="0" MinWidth="0"
@@ -490,11 +551,7 @@
CornerRadius="5" CornerRadius="5"
HorizontalAlignment="Stretch" HorizontalAlignment="Stretch"
Margin="0,-1,0,0"> Margin="0,-1,0,0">
<Grid IsVisible="{Binding ParentModel.HasLed}"> <Grid IsVisible="{Binding ParentModel.HasLed}" ColumnDefinitions="*,Auto">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<CheckBox <CheckBox
Margin="10, 10, 5, 10" Margin="10, 10, 5, 10"
MinWidth="0" MinWidth="0"
@@ -526,15 +583,7 @@
CornerRadius="5"> CornerRadius="5">
<Grid <Grid
Margin="10" Margin="10"
HorizontalAlignment="Stretch"> HorizontalAlignment="Stretch" ColumnDefinitions="*,*" RowDefinitions="*,*">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<StackPanel <StackPanel
Grid.Column="1" Grid.Column="1"
Grid.Row="0" Grid.Row="0"

View File

@@ -4,6 +4,7 @@ using Avalonia.Controls.Primitives;
using Avalonia.Input; using Avalonia.Input;
using Avalonia.Interactivity; using Avalonia.Interactivity;
using Avalonia.LogicalTree; using Avalonia.LogicalTree;
using Ryujinx.Ava.UI.Controls;
using Ryujinx.Ava.UI.Helpers; using Ryujinx.Ava.UI.Helpers;
using Ryujinx.Ava.UI.ViewModels.Input; using Ryujinx.Ava.UI.ViewModels.Input;
using Ryujinx.Common.Configuration.Hid.Controller; using Ryujinx.Common.Configuration.Hid.Controller;
@@ -14,7 +15,7 @@ using StickInputId = Ryujinx.Common.Configuration.Hid.Controller.StickInputId;
namespace Ryujinx.Ava.UI.Views.Input namespace Ryujinx.Ava.UI.Views.Input
{ {
public partial class ControllerInputView : UserControl public partial class ControllerInputView : RyujinxControl<ControllerInputViewModel>
{ {
private ButtonKeyAssigner _currentAssigner; private ButtonKeyAssigner _currentAssigner;
@@ -217,20 +218,12 @@ namespace Ryujinx.Ava.UI.Views.Input
PointerPressed -= MouseClick; PointerPressed -= MouseClick;
} }
private IButtonAssigner CreateButtonAssigner(bool forStick) private IButtonAssigner CreateButtonAssigner(bool forStick) =>
{ new GamepadButtonAssigner(
IButtonAssigner assigner; ViewModel.ParentModel.SelectedGamepad,
(ViewModel.ParentModel.Config as StandardControllerInputConfig).TriggerThreshold,
ControllerInputViewModel controllerInputViewModel = DataContext as ControllerInputViewModel;
assigner = new GamepadButtonAssigner(
controllerInputViewModel.ParentModel.SelectedGamepad,
(controllerInputViewModel.ParentModel.Config as StandardControllerInputConfig).TriggerThreshold,
forStick); forStick);
return assigner;
}
protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e) protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e)
{ {
base.OnDetachedFromVisualTree(e); base.OnDetachedFromVisualTree(e);

View File

@@ -35,22 +35,13 @@
Margin="0 0 0 5" Margin="0 0 0 5"
Orientation="Vertical" Orientation="Vertical"
Spacing="5"> Spacing="5">
<Grid> <Grid ColumnDefinitions="*,10,*">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="10" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<!-- Player Selection --> <!-- Player Selection -->
<Grid <Grid
Grid.Column="0" Grid.Column="0"
Margin="2" Margin="2"
HorizontalAlignment="Stretch" HorizontalAlignment="Stretch"
VerticalAlignment="Center"> VerticalAlignment="Center" ColumnDefinitions="Auto,*">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock <TextBlock
Margin="5,0,10,0" Margin="5,0,10,0"
Width="90" Width="90"
@@ -77,14 +68,7 @@
Grid.Column="2" Grid.Column="2"
Margin="2" Margin="2"
HorizontalAlignment="Stretch" HorizontalAlignment="Stretch"
VerticalAlignment="Center"> VerticalAlignment="Center" ColumnDefinitions="Auto,*,Auto,Auto,Auto">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBlock <TextBlock
Margin="5,0,10,0" Margin="5,0,10,0"
Width="90" Width="90"
@@ -139,22 +123,12 @@
</Grid> </Grid>
</Grid> </Grid>
<Separator /> <Separator />
<Grid> <Grid ColumnDefinitions="*,10,*">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="10" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<!-- Input Device --> <!-- Input Device -->
<Grid <Grid
Grid.Column="0" Grid.Column="0"
Margin="2" Margin="2"
HorizontalAlignment="Stretch"> HorizontalAlignment="Stretch" ColumnDefinitions="Auto,*,Auto">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock <TextBlock
Grid.Column="0" Grid.Column="0"
Margin="5,0,10,0" Margin="5,0,10,0"
@@ -186,11 +160,7 @@
Grid.Column="2" Grid.Column="2"
Margin="2" Margin="2"
HorizontalAlignment="Stretch" HorizontalAlignment="Stretch"
VerticalAlignment="Center"> VerticalAlignment="Center" ColumnDefinitions="Auto,*">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock <TextBlock
Margin="5,0,10,0" Margin="5,0,10,0"
Width="90" Width="90"

View File

@@ -1,19 +1,19 @@
using Avalonia.Controls; using Avalonia.Controls;
using Ryujinx.Ava.Common.Locale; using Ryujinx.Ava.Common.Locale;
using Ryujinx.Ava.UI.Controls;
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.Input; using Ryujinx.Ava.UI.ViewModels.Input;
namespace Ryujinx.Ava.UI.Views.Input namespace Ryujinx.Ava.UI.Views.Input
{ {
public partial class InputView : UserControl public partial class InputView : RyujinxControl<InputViewModel>
{ {
private bool _dialogOpen; private bool _dialogOpen;
private InputViewModel ViewModel { get; set; }
public InputView() public InputView()
{ {
DataContext = ViewModel = new InputViewModel(this); ViewModel = new InputViewModel(this);
InitializeComponent(); InitializeComponent();
} }

View File

@@ -32,12 +32,7 @@
<!-- Button / JoyStick Settings --> <!-- Button / JoyStick Settings -->
<Grid <Grid
Name="SettingButtons" Name="SettingButtons"
MinHeight="450"> MinHeight="450" ColumnDefinitions="Auto,*,Auto">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<!-- Left Controls --> <!-- Left Controls -->
<StackPanel <StackPanel
Orientation="Vertical" Orientation="Vertical"
@@ -52,15 +47,7 @@
CornerRadius="5"> CornerRadius="5">
<Grid <Grid
Margin="10" Margin="10"
HorizontalAlignment="Stretch"> HorizontalAlignment="Stretch" ColumnDefinitions="*,*" RowDefinitions="*,*">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<StackPanel <StackPanel
Grid.Column="0" Grid.Column="0"
Grid.Row="0" Grid.Row="0"
@@ -309,12 +296,79 @@
HorizontalAlignment="Stretch" HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"> VerticalAlignment="Stretch">
<!-- Controller Picture --> <!-- Controller Picture -->
<Image <Border
BorderBrush="{DynamicResource ThemeControlBorderColor}"
BorderThickness="1"
CornerRadius="5"
Margin="0,10" Margin="0,10"
MaxHeight="300" MinHeight="90">
HorizontalAlignment="Stretch" <StackPanel
VerticalAlignment="Stretch" Margin="10"
Source="{Binding Image}" /> Orientation="Horizontal"
Spacing="20"
HorizontalAlignment="Center">
<Border
BorderBrush="{DynamicResource ThemeControlBorderColor}"
BorderThickness="1"
CornerRadius="5"
Height="{Binding Visualizer.UiStickBorderSize}"
Width="{Binding Visualizer.UiStickBorderSize}"
IsVisible="{Binding IsLeft}">
<Canvas
Background="{DynamicResource ThemeBackgroundColor}"
Height="{Binding Visualizer.UiCanvasSize}"
Width="{Binding Visualizer.UiCanvasSize}">
<Grid
Height="{Binding Visualizer.UiCanvasSize}"
Width="{Binding Visualizer.UiCanvasSize}"
Background="{DynamicResource ThemeBackgroundColor}">
<Ellipse
HorizontalAlignment="Center"
Stroke="Black"
StrokeThickness="1"
Width="{Binding Visualizer.UiCanvasSize}"
Height="{Binding Visualizer.UiCanvasSize}"/>
</Grid>
<Ellipse
Fill="Red"
Width="{Binding Visualizer.UiStickCircumference}"
Height="{Binding Visualizer.UiStickCircumference}"
Canvas.Bottom="{Binding Visualizer.UiStickLeftY}"
Canvas.Left="{Binding Visualizer.UiStickLeftX}" />
</Canvas>
</Border>
<Border
BorderBrush="{DynamicResource ThemeControlBorderColor}"
BorderThickness="1"
CornerRadius="5"
Height="{Binding Visualizer.UiStickBorderSize}"
Width="{Binding Visualizer.UiStickBorderSize}"
IsVisible="{Binding IsRight}">
<Canvas
Background="{DynamicResource ThemeBackgroundColor}"
Height="{Binding Visualizer.UiCanvasSize}"
Width="{Binding Visualizer.UiCanvasSize}">
<Grid
Height="{Binding Visualizer.UiCanvasSize}"
Width="{Binding Visualizer.UiCanvasSize}"
Background="{DynamicResource ThemeBackgroundColor}">
<Ellipse
HorizontalAlignment="Center"
Stroke="Black"
StrokeThickness="1"
Width="{Binding Visualizer.UiCanvasSize}"
Height="{Binding Visualizer.UiCanvasSize}"/>
</Grid>
<Ellipse
Fill="Red"
Width="{Binding Visualizer.UiStickCircumference}"
Height="{Binding Visualizer.UiStickCircumference}"
Canvas.Bottom="{Binding Visualizer.UiStickRightY}"
Canvas.Left="{Binding Visualizer.UiStickRightX}" />
</Canvas>
</Border>
</StackPanel>
</Border>
<Border <Border
BorderBrush="{DynamicResource ThemeControlBorderColor}" BorderBrush="{DynamicResource ThemeControlBorderColor}"
BorderThickness="1" BorderThickness="1"
@@ -413,15 +467,7 @@
CornerRadius="5"> CornerRadius="5">
<Grid <Grid
Margin="10" Margin="10"
HorizontalAlignment="Stretch"> HorizontalAlignment="Stretch" ColumnDefinitions="*,*" RowDefinitions="*,*">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<StackPanel <StackPanel
Grid.Column="1" Grid.Column="1"
Grid.Row="0" Grid.Row="0"

View File

@@ -4,6 +4,7 @@ using Avalonia.Controls.Primitives;
using Avalonia.Input; using Avalonia.Input;
using Avalonia.Interactivity; using Avalonia.Interactivity;
using Avalonia.LogicalTree; using Avalonia.LogicalTree;
using Ryujinx.Ava.UI.Controls;
using Ryujinx.Ava.UI.Helpers; using Ryujinx.Ava.UI.Helpers;
using Ryujinx.Ava.UI.ViewModels.Input; using Ryujinx.Ava.UI.ViewModels.Input;
using Ryujinx.Input; using Ryujinx.Input;
@@ -13,7 +14,7 @@ using Key = Ryujinx.Common.Configuration.Hid.Key;
namespace Ryujinx.Ava.UI.Views.Input namespace Ryujinx.Ava.UI.Views.Input
{ {
public partial class KeyboardInputView : UserControl public partial class KeyboardInputView : RyujinxControl<KeyboardInputViewModel>
{ {
private ButtonKeyAssigner _currentAssigner; private ButtonKeyAssigner _currentAssigner;
@@ -60,106 +61,103 @@ namespace Ryujinx.Ava.UI.Views.Input
PointerPressed += MouseClick; PointerPressed += MouseClick;
if (DataContext is not KeyboardInputViewModel viewModel)
return;
IKeyboard keyboard = IKeyboard keyboard =
(IKeyboard)viewModel.ParentModel.AvaloniaKeyboardDriver.GetGamepad("0"); // Open Avalonia keyboard for cancel operations. (IKeyboard)ViewModel.ParentModel.AvaloniaKeyboardDriver.GetGamepad("0"); // Open Avalonia keyboard for cancel operations.
IButtonAssigner assigner = IButtonAssigner assigner =
new KeyboardKeyAssigner((IKeyboard)viewModel.ParentModel.SelectedGamepad); new KeyboardKeyAssigner((IKeyboard)ViewModel.ParentModel.SelectedGamepad);
_currentAssigner.ButtonAssigned += (_, e) => _currentAssigner.ButtonAssigned += (_, be) =>
{ {
if (e.ButtonValue.HasValue) if (be.ButtonValue.HasValue)
{ {
Button buttonValue = e.ButtonValue.Value; Button buttonValue = be.ButtonValue.Value;
viewModel.ParentModel.IsModified = true; ViewModel.ParentModel.IsModified = true;
switch (button.Name) switch (button.Name)
{ {
case "ButtonZl": case "ButtonZl":
viewModel.Config.ButtonZl = buttonValue.AsHidType<Key>(); ViewModel.Config.ButtonZl = buttonValue.AsHidType<Key>();
break; break;
case "ButtonL": case "ButtonL":
viewModel.Config.ButtonL = buttonValue.AsHidType<Key>(); ViewModel.Config.ButtonL = buttonValue.AsHidType<Key>();
break; break;
case "ButtonMinus": case "ButtonMinus":
viewModel.Config.ButtonMinus = buttonValue.AsHidType<Key>(); ViewModel.Config.ButtonMinus = buttonValue.AsHidType<Key>();
break; break;
case "LeftStickButton": case "LeftStickButton":
viewModel.Config.LeftStickButton = buttonValue.AsHidType<Key>(); ViewModel.Config.LeftStickButton = buttonValue.AsHidType<Key>();
break; break;
case "LeftStickUp": case "LeftStickUp":
viewModel.Config.LeftStickUp = buttonValue.AsHidType<Key>(); ViewModel.Config.LeftStickUp = buttonValue.AsHidType<Key>();
break; break;
case "LeftStickDown": case "LeftStickDown":
viewModel.Config.LeftStickDown = buttonValue.AsHidType<Key>(); ViewModel.Config.LeftStickDown = buttonValue.AsHidType<Key>();
break; break;
case "LeftStickRight": case "LeftStickRight":
viewModel.Config.LeftStickRight = buttonValue.AsHidType<Key>(); ViewModel.Config.LeftStickRight = buttonValue.AsHidType<Key>();
break; break;
case "LeftStickLeft": case "LeftStickLeft":
viewModel.Config.LeftStickLeft = buttonValue.AsHidType<Key>(); ViewModel.Config.LeftStickLeft = buttonValue.AsHidType<Key>();
break; break;
case "DpadUp": case "DpadUp":
viewModel.Config.DpadUp = buttonValue.AsHidType<Key>(); ViewModel.Config.DpadUp = buttonValue.AsHidType<Key>();
break; break;
case "DpadDown": case "DpadDown":
viewModel.Config.DpadDown = buttonValue.AsHidType<Key>(); ViewModel.Config.DpadDown = buttonValue.AsHidType<Key>();
break; break;
case "DpadLeft": case "DpadLeft":
viewModel.Config.DpadLeft = buttonValue.AsHidType<Key>(); ViewModel.Config.DpadLeft = buttonValue.AsHidType<Key>();
break; break;
case "DpadRight": case "DpadRight":
viewModel.Config.DpadRight = buttonValue.AsHidType<Key>(); ViewModel.Config.DpadRight = buttonValue.AsHidType<Key>();
break; break;
case "LeftButtonSr": case "LeftButtonSr":
viewModel.Config.LeftButtonSr = buttonValue.AsHidType<Key>(); ViewModel.Config.LeftButtonSr = buttonValue.AsHidType<Key>();
break; break;
case "LeftButtonSl": case "LeftButtonSl":
viewModel.Config.LeftButtonSl = buttonValue.AsHidType<Key>(); ViewModel.Config.LeftButtonSl = buttonValue.AsHidType<Key>();
break; break;
case "RightButtonSr": case "RightButtonSr":
viewModel.Config.RightButtonSr = buttonValue.AsHidType<Key>(); ViewModel.Config.RightButtonSr = buttonValue.AsHidType<Key>();
break; break;
case "RightButtonSl": case "RightButtonSl":
viewModel.Config.RightButtonSl = buttonValue.AsHidType<Key>(); ViewModel.Config.RightButtonSl = buttonValue.AsHidType<Key>();
break; break;
case "ButtonZr": case "ButtonZr":
viewModel.Config.ButtonZr = buttonValue.AsHidType<Key>(); ViewModel.Config.ButtonZr = buttonValue.AsHidType<Key>();
break; break;
case "ButtonR": case "ButtonR":
viewModel.Config.ButtonR = buttonValue.AsHidType<Key>(); ViewModel.Config.ButtonR = buttonValue.AsHidType<Key>();
break; break;
case "ButtonPlus": case "ButtonPlus":
viewModel.Config.ButtonPlus = buttonValue.AsHidType<Key>(); ViewModel.Config.ButtonPlus = buttonValue.AsHidType<Key>();
break; break;
case "ButtonA": case "ButtonA":
viewModel.Config.ButtonA = buttonValue.AsHidType<Key>(); ViewModel.Config.ButtonA = buttonValue.AsHidType<Key>();
break; break;
case "ButtonB": case "ButtonB":
viewModel.Config.ButtonB = buttonValue.AsHidType<Key>(); ViewModel.Config.ButtonB = buttonValue.AsHidType<Key>();
break; break;
case "ButtonX": case "ButtonX":
viewModel.Config.ButtonX = buttonValue.AsHidType<Key>(); ViewModel.Config.ButtonX = buttonValue.AsHidType<Key>();
break; break;
case "ButtonY": case "ButtonY":
viewModel.Config.ButtonY = buttonValue.AsHidType<Key>(); ViewModel.Config.ButtonY = buttonValue.AsHidType<Key>();
break; break;
case "RightStickButton": case "RightStickButton":
viewModel.Config.RightStickButton = buttonValue.AsHidType<Key>(); ViewModel.Config.RightStickButton = buttonValue.AsHidType<Key>();
break; break;
case "RightStickUp": case "RightStickUp":
viewModel.Config.RightStickUp = buttonValue.AsHidType<Key>(); ViewModel.Config.RightStickUp = buttonValue.AsHidType<Key>();
break; break;
case "RightStickDown": case "RightStickDown":
viewModel.Config.RightStickDown = buttonValue.AsHidType<Key>(); ViewModel.Config.RightStickDown = buttonValue.AsHidType<Key>();
break; break;
case "RightStickRight": case "RightStickRight":
viewModel.Config.RightStickRight = buttonValue.AsHidType<Key>(); ViewModel.Config.RightStickRight = buttonValue.AsHidType<Key>();
break; break;
case "RightStickLeft": case "RightStickLeft":
viewModel.Config.RightStickLeft = buttonValue.AsHidType<Key>(); ViewModel.Config.RightStickLeft = buttonValue.AsHidType<Key>();
break; break;
} }
} }

View File

@@ -2,19 +2,18 @@
using Avalonia.Controls; using Avalonia.Controls;
using FluentAvalonia.UI.Controls; using FluentAvalonia.UI.Controls;
using Ryujinx.Ava.Common.Locale; using Ryujinx.Ava.Common.Locale;
using Ryujinx.Ava.UI.Controls;
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 System.Threading.Tasks; using System.Threading.Tasks;
namespace Ryujinx.UI.Views.Input namespace Ryujinx.UI.Views.Input
{ {
public partial class LedInputView : UserControl public partial class LedInputView : RyujinxControl<LedInputViewModel>
{ {
private readonly LedInputViewModel _viewModel;
public LedInputView(ControllerInputViewModel viewModel) public LedInputView(ControllerInputViewModel viewModel)
{ {
DataContext = _viewModel = new LedInputViewModel ViewModel = new LedInputViewModel
{ {
ParentModel = viewModel.ParentModel, ParentModel = viewModel.ParentModel,
TurnOffLed = viewModel.Config.TurnOffLed, TurnOffLed = viewModel.Config.TurnOffLed,
@@ -29,20 +28,18 @@ namespace Ryujinx.UI.Views.Input
private void ColorPickerButton_OnColorChanged(ColorPickerButton sender, ColorButtonColorChangedEventArgs args) private void ColorPickerButton_OnColorChanged(ColorPickerButton sender, ColorButtonColorChangedEventArgs args)
{ {
if (!args.NewColor.HasValue) return; if (!args.NewColor.HasValue) return;
if (DataContext is not LedInputViewModel lvm) return; if (!ViewModel.EnableLedChanging) return;
if (!lvm.EnableLedChanging) return; if (ViewModel.TurnOffLed) return;
if (lvm.TurnOffLed) return;
lvm.ParentModel.SelectedGamepad.SetLed(args.NewColor.Value.ToUInt32()); ViewModel.ParentModel.SelectedGamepad.SetLed(args.NewColor.Value.ToUInt32());
} }
private void ColorPickerButton_OnAttachedToVisualTree(object sender, VisualTreeAttachmentEventArgs e) private void ColorPickerButton_OnAttachedToVisualTree(object sender, VisualTreeAttachmentEventArgs e)
{ {
if (DataContext is not LedInputViewModel lvm) return; if (!ViewModel.EnableLedChanging) return;
if (!lvm.EnableLedChanging) return; if (ViewModel.TurnOffLed) return;
if (lvm.TurnOffLed) return;
lvm.ParentModel.SelectedGamepad.SetLed(lvm.LedColor.ToUInt32()); ViewModel.ParentModel.SelectedGamepad.SetLed(ViewModel.LedColor.ToUInt32());
} }
public static async Task Show(ControllerInputViewModel viewModel) public static async Task Show(ControllerInputViewModel viewModel)
@@ -57,13 +54,13 @@ namespace Ryujinx.UI.Views.Input
CloseButtonText = LocaleManager.Instance[LocaleKeys.ControllerSettingsClose], CloseButtonText = LocaleManager.Instance[LocaleKeys.ControllerSettingsClose],
Content = content, Content = content,
}; };
contentDialog.PrimaryButtonClick += (sender, args) => contentDialog.PrimaryButtonClick += (_, _) =>
{ {
GamepadInputConfig config = viewModel.Config; GamepadInputConfig config = viewModel.Config;
config.EnableLedChanging = content._viewModel.EnableLedChanging; config.EnableLedChanging = content.ViewModel.EnableLedChanging;
config.LedColor = content._viewModel.LedColor; config.LedColor = content.ViewModel.LedColor;
config.UseRainbowLed = content._viewModel.UseRainbowLed; config.UseRainbowLed = content.ViewModel.UseRainbowLed;
config.TurnOffLed = content._viewModel.TurnOffLed; config.TurnOffLed = content.ViewModel.TurnOffLed;
}; };
await contentDialog.ShowAsync(); await contentDialog.ShowAsync();

View File

@@ -11,11 +11,7 @@
x:Class="Ryujinx.Ava.UI.Views.Input.MotionInputView" x:Class="Ryujinx.Ava.UI.Views.Input.MotionInputView"
x:DataType="viewModels:MotionInputViewModel" x:DataType="viewModels:MotionInputViewModel"
Focusable="True"> Focusable="True">
<Grid Margin="10"> <Grid Margin="10" RowDefinitions="Auto,*">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition />
</Grid.RowDefinitions>
<StackPanel Orientation="Vertical"> <StackPanel Orientation="Vertical">
<StackPanel <StackPanel
Orientation="Horizontal" Orientation="Horizontal"
@@ -80,11 +76,7 @@
BorderThickness="1" BorderThickness="1"
CornerRadius="5" CornerRadius="5"
HorizontalAlignment="Stretch"> HorizontalAlignment="Stretch">
<Grid VerticalAlignment="Top"> <Grid VerticalAlignment="Top" RowDefinitions="Auto,*">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<StackPanel <StackPanel
Grid.Row="1" Grid.Row="1"
HorizontalAlignment="Center" HorizontalAlignment="Center"
@@ -118,15 +110,7 @@
Text="{Binding DsuServerPort, Mode=TwoWay}" /> Text="{Binding DsuServerPort, Mode=TwoWay}" />
</StackPanel> </StackPanel>
<StackPanel Orientation="Vertical"> <StackPanel Orientation="Vertical">
<Grid> <Grid RowDefinitions="*,*" ColumnDefinitions="*,*">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<TextBlock <TextBlock
Margin="0,10,0,0" Margin="0,10,0,0"
VerticalAlignment="Center" VerticalAlignment="Center"

View File

@@ -1,16 +1,15 @@
using Avalonia.Controls; using Avalonia.Controls;
using FluentAvalonia.UI.Controls; using FluentAvalonia.UI.Controls;
using Ryujinx.Ava.Common.Locale; using Ryujinx.Ava.Common.Locale;
using Ryujinx.Ava.UI.Controls;
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 System.Threading.Tasks; using System.Threading.Tasks;
namespace Ryujinx.Ava.UI.Views.Input namespace Ryujinx.Ava.UI.Views.Input
{ {
public partial class MotionInputView : UserControl public partial class MotionInputView : RyujinxControl<MotionInputViewModel>
{ {
private readonly MotionInputViewModel _viewModel;
public MotionInputView() public MotionInputView()
{ {
InitializeComponent(); InitializeComponent();
@@ -20,7 +19,7 @@ namespace Ryujinx.Ava.UI.Views.Input
{ {
GamepadInputConfig config = viewModel.Config; GamepadInputConfig config = viewModel.Config;
_viewModel = new MotionInputViewModel ViewModel = new MotionInputViewModel
{ {
Slot = config.Slot, Slot = config.Slot,
AltSlot = config.AltSlot, AltSlot = config.AltSlot,
@@ -33,7 +32,6 @@ namespace Ryujinx.Ava.UI.Views.Input
}; };
InitializeComponent(); InitializeComponent();
DataContext = _viewModel;
} }
public static async Task Show(ControllerInputViewModel viewModel) public static async Task Show(ControllerInputViewModel viewModel)
@@ -48,17 +46,17 @@ namespace Ryujinx.Ava.UI.Views.Input
CloseButtonText = LocaleManager.Instance[LocaleKeys.ControllerSettingsClose], CloseButtonText = LocaleManager.Instance[LocaleKeys.ControllerSettingsClose],
Content = content, Content = content,
}; };
contentDialog.PrimaryButtonClick += (sender, args) => contentDialog.PrimaryButtonClick += (_, _) =>
{ {
GamepadInputConfig config = viewModel.Config; GamepadInputConfig config = viewModel.Config;
config.Slot = content._viewModel.Slot; config.Slot = content.ViewModel.Slot;
config.Sensitivity = content._viewModel.Sensitivity; config.Sensitivity = content.ViewModel.Sensitivity;
config.GyroDeadzone = content._viewModel.GyroDeadzone; config.GyroDeadzone = content.ViewModel.GyroDeadzone;
config.AltSlot = content._viewModel.AltSlot; config.AltSlot = content.ViewModel.AltSlot;
config.DsuServerHost = content._viewModel.DsuServerHost; config.DsuServerHost = content.ViewModel.DsuServerHost;
config.DsuServerPort = content._viewModel.DsuServerPort; config.DsuServerPort = content.ViewModel.DsuServerPort;
config.EnableCemuHookMotion = content._viewModel.EnableCemuHookMotion; config.EnableCemuHookMotion = content.ViewModel.EnableCemuHookMotion;
config.MirrorInput = content._viewModel.MirrorInput; config.MirrorInput = content.ViewModel.MirrorInput;
}; };
await contentDialog.ShowAsync(); await contentDialog.ShowAsync();

View File

@@ -10,11 +10,7 @@
x:Class="Ryujinx.Ava.UI.Views.Input.RumbleInputView" x:Class="Ryujinx.Ava.UI.Views.Input.RumbleInputView"
x:DataType="viewModels:RumbleInputViewModel" x:DataType="viewModels:RumbleInputViewModel"
Focusable="True"> Focusable="True">
<Grid Margin="10"> <Grid Margin="10" RowDefinitions="Auto,*">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition />
</Grid.RowDefinitions>
<StackPanel Orientation="Vertical"> <StackPanel Orientation="Vertical">
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal">
<TextBlock <TextBlock

View File

@@ -1,16 +1,15 @@
using Avalonia.Controls; using Avalonia.Controls;
using FluentAvalonia.UI.Controls; using FluentAvalonia.UI.Controls;
using Ryujinx.Ava.Common.Locale; using Ryujinx.Ava.Common.Locale;
using Ryujinx.Ava.UI.Controls;
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 System.Threading.Tasks; using System.Threading.Tasks;
namespace Ryujinx.Ava.UI.Views.Input namespace Ryujinx.Ava.UI.Views.Input
{ {
public partial class RumbleInputView : UserControl public partial class RumbleInputView : RyujinxControl<RumbleInputViewModel>
{ {
private readonly RumbleInputViewModel _viewModel;
public RumbleInputView() public RumbleInputView()
{ {
InitializeComponent(); InitializeComponent();
@@ -20,15 +19,13 @@ namespace Ryujinx.Ava.UI.Views.Input
{ {
GamepadInputConfig config = viewModel.Config; GamepadInputConfig config = viewModel.Config;
_viewModel = new RumbleInputViewModel ViewModel = new RumbleInputViewModel
{ {
StrongRumble = config.StrongRumble, StrongRumble = config.StrongRumble,
WeakRumble = config.WeakRumble, WeakRumble = config.WeakRumble,
}; };
InitializeComponent(); InitializeComponent();
DataContext = _viewModel;
} }
public static async Task Show(ControllerInputViewModel viewModel) public static async Task Show(ControllerInputViewModel viewModel)
@@ -44,11 +41,11 @@ namespace Ryujinx.Ava.UI.Views.Input
Content = content, Content = content,
}; };
contentDialog.PrimaryButtonClick += (sender, args) => contentDialog.PrimaryButtonClick += (_, _) =>
{ {
GamepadInputConfig config = viewModel.Config; GamepadInputConfig config = viewModel.Config;
config.StrongRumble = content._viewModel.StrongRumble; config.StrongRumble = content.ViewModel.StrongRumble;
config.WeakRumble = content._viewModel.WeakRumble; config.WeakRumble = content.ViewModel.WeakRumble;
}; };
await contentDialog.ShowAsync(); await contentDialog.ShowAsync();

View File

@@ -6,13 +6,14 @@ using Gommon;
using LibHac.Common; using LibHac.Common;
using LibHac.Ns; using LibHac.Ns;
using Ryujinx.Ava.Common.Locale; using Ryujinx.Ava.Common.Locale;
using Ryujinx.Ava.UI.Controls;
using Ryujinx.Ava.UI.Helpers; using Ryujinx.Ava.UI.Helpers;
using Ryujinx.Ava.UI.ViewModels; using Ryujinx.Ava.UI.ViewModels;
using Ryujinx.Ava.UI.Windows; using Ryujinx.Ava.UI.Windows;
using Ryujinx.Ava.Utilities; using Ryujinx.Ava.Utilities;
using Ryujinx.Ava.Utilities.AppLibrary; using Ryujinx.Ava.Systems.AppLibrary;
using Ryujinx.Ava.Utilities.Compat; using Ryujinx.Ava.Systems.Configuration;
using Ryujinx.Ava.Utilities.Configuration; using Ryujinx.Ava.UI.Views.Misc;
using Ryujinx.Common; using Ryujinx.Common;
using Ryujinx.Common.Helper; using Ryujinx.Common.Helper;
using Ryujinx.Common.Utilities; using Ryujinx.Common.Utilities;
@@ -25,10 +26,9 @@ using System.Threading.Tasks;
namespace Ryujinx.Ava.UI.Views.Main namespace Ryujinx.Ava.UI.Views.Main
{ {
public partial class MainMenuBarView : UserControl public partial class MainMenuBarView : RyujinxControl<MainWindowViewModel>
{ {
public MainWindow Window { get; private set; } public MainWindow Window { get; private set; }
public MainWindowViewModel ViewModel { get; private set; }
public MainMenuBarView() public MainMenuBarView()
{ {
@@ -51,7 +51,7 @@ namespace Ryujinx.Ava.UI.Views.Main
UninstallFileTypesMenuItem.Command = Commands.Create(UninstallFileTypes); UninstallFileTypesMenuItem.Command = Commands.Create(UninstallFileTypes);
XciTrimmerMenuItem.Command = Commands.Create(XCITrimmerWindow.Show); XciTrimmerMenuItem.Command = Commands.Create(XCITrimmerWindow.Show);
AboutWindowMenuItem.Command = Commands.Create(AboutWindow.Show); AboutWindowMenuItem.Command = Commands.Create(AboutWindow.Show);
CompatibilityListMenuItem.Command = Commands.Create(() => CompatibilityList.Show()); CompatibilityListMenuItem.Command = Commands.Create(() => CompatibilityListWindow.Show());
UpdateMenuItem.Command = MainWindowViewModel.UpdateCommand; UpdateMenuItem.Command = MainWindowViewModel.UpdateCommand;
@@ -73,7 +73,7 @@ namespace Ryujinx.Ava.UI.Views.Main
{ {
Content = $".{it.FileName}", Content = $".{it.FileName}",
IsChecked = it.FileType.GetConfigValue(ConfigurationState.Instance.UI.ShownFileTypes), IsChecked = it.FileType.GetConfigValue(ConfigurationState.Instance.UI.ShownFileTypes),
Command = MiniCommand.Create(() => Window.ToggleFileType(it.FileName)) Command = Commands.Create(() => Window.ToggleFileType(it.FileName))
} }
); );
@@ -108,7 +108,7 @@ namespace Ryujinx.Ava.UI.Views.Main
Margin = new Thickness(3, 0, 3, 0), Margin = new Thickness(3, 0, 3, 0),
HorizontalAlignment = HorizontalAlignment.Stretch, HorizontalAlignment = HorizontalAlignment.Stretch,
Header = languageName, Header = languageName,
Command = MiniCommand.Create(() => MainWindowViewModel.ChangeLanguage(language)) Command = Commands.Create(() => MainWindowViewModel.ChangeLanguage(language))
}; };
yield return menuItem; yield return menuItem;

Some files were not shown because too many files have changed in this diff Show More