Compare commits

..

17 Commits

Author SHA1 Message Date
Evan Husted
0bec0edcd4 Merge 3b447b764e into 7085bafa60 2025-01-29 02:42:08 +00:00
Evan Husted
3b447b764e Merge branch 'master' into xeyes 2025-01-28 01:45:49 -06:00
Evan Husted
849fd0199e Merge branch 'master' into xeyes 2025-01-26 17:33:58 -06:00
Evan Husted
57e26114e8 Merge branch 'master' into xeyes 2025-01-25 21:56:40 -06:00
Evan Husted
6a283190b3 Add the controller image back 2025-01-24 22:24:02 -06:00
MutantAura
85547874c8 Consolidate most logic into StickVisualizer. 2025-01-24 20:08:58 -06:00
MutantAura
16ca8e5005 Move most logic into new StickVisualizer class and add keyboard support. 2025-01-24 20:01:36 -06:00
MutantAura
cfa5ad0757 Simplfy clamping and fix bug on window close. 2025-01-24 19:58:17 -06:00
MutantAura
43ece083b2 Move some backing fields to match others.
formatting pt.2
2025-01-24 19:57:11 -06:00
MutantAura
e1f5c501b0 Fix some issues with stick magnitude. 2025-01-24 19:56:21 -06:00
MutantAura
ffe366d953 Cleanup AXAML and hide sticks when only one is present on guest controller. 2025-01-24 19:52:57 -06:00
MutantAura
75c7a29278 style and analyzers 2025-01-24 19:52:52 -06:00
MutantAura
3a0d9c1435 whitespace 2025-01-24 19:52:47 -06:00
MutantAura
93d1476a2a Remove unused grid definitions. 2025-01-24 19:52:39 -06:00
MutantAura
ce13830063 Clean up some magic numbers between code and axaml. 2025-01-24 19:52:24 -06:00
MutantAura
aa3f2824e0 Polish the aesthetic and include deadzone visualization. 2025-01-24 19:51:44 -06:00
MutantAura
d2bb580aea Initial implementation of analog stick visualization. 2025-01-24 19:50:09 -06:00
42 changed files with 677 additions and 165 deletions

View File

@@ -4,7 +4,6 @@ using ARMeilleure.CodeGen.Unwinding;
using ARMeilleure.Common;
using ARMeilleure.Memory;
using ARMeilleure.State;
using Humanizer;
using Ryujinx.Common;
using Ryujinx.Common.Configuration;
using Ryujinx.Common.Logging;
@@ -924,11 +923,15 @@ namespace ARMeilleure.Translation.PTC
sw.Stop();
PtcStateChanged?.Invoke(PtcLoadingState.Loaded, _translateCount, _translateTotalCount);
Logger.Info?.Print(LogClass.Ptc,
$"{_translateCount} of {_translateTotalCount} functions translated in {sw.Elapsed.TotalSeconds} seconds " +
$"| {"function".ToQuantity(_translateTotalCount - _translateCount)} blacklisted " +
$"| Thread count: {degreeOfParallelism}");
if (_translateCount == _translateTotalCount)
{
Logger.Info?.Print(LogClass.Ptc, $"{_translateCount} of {_translateTotalCount} functions translated | Thread count: {degreeOfParallelism} in {sw.Elapsed.TotalSeconds} s");
}
else
{
Logger.Info?.Print(LogClass.Ptc, $"{_translateCount} of {_translateTotalCount} functions translated | {_translateTotalCount - _translateCount} function{(_translateTotalCount - _translateCount != 1 ? "s" : "")} blacklisted | Thread count: {degreeOfParallelism} in {sw.Elapsed.TotalSeconds} s");
}
Thread preSaveThread = new(PreSave)
{

View File

@@ -76,7 +76,7 @@ namespace Ryujinx.Graphics.Metal
return model;
}
return string.Empty;
return "";
}
}
}

View File

@@ -218,7 +218,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Msl
foreach (MemoryDefinition memory in memories)
{
string arraySize = string.Empty;
string arraySize = "";
if ((memory.Type & AggregateType.Array) != 0)
{
arraySize = $"[{memory.ArrayLength}]";
@@ -240,7 +240,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Msl
BufferDefinition buffer = buffers[i];
bool needsPadding = buffer.Layout == BufferLayout.Std140;
string fsiSuffix = !constant && fsi ? " [[raster_order_group(0)]]" : string.Empty;
string fsiSuffix = !constant && fsi ? " [[raster_order_group(0)]]" : "";
bufferDec[i] = $"{addressSpace} {Defaults.StructPrefix}_{buffer.Name}* {buffer.Name}{fsiSuffix};";
@@ -257,7 +257,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Msl
type &= ~AggregateType.Array;
string typeName = GetVarTypeName(type);
string arraySuffix = string.Empty;
string arraySuffix = "";
if (field.Type.HasFlag(AggregateType.Array))
{
@@ -353,7 +353,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Msl
imageTypeName = $"array<{imageTypeName}, {image.ArrayLength}>";
}
string fsiSuffix = fsi ? " [[raster_order_group(0)]]" : string.Empty;
string fsiSuffix = fsi ? " [[raster_order_group(0)]]" : "";
imageDec[i] = $"{imageTypeName} {image.Name}{fsiSuffix};";
}
@@ -454,7 +454,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Msl
IoVariable.VertexIndex => "[[vertex_id]]",
// IoVariable.PointCoord => "[[point_coord]]",
IoVariable.UserDefined => context.Definitions.Stage == ShaderStage.Fragment ? $"[[user(loc{ioDefinition.Location})]]" : $"[[attribute({ioDefinition.Location})]]",
_ => string.Empty
_ => ""
};
context.AppendLine($"{type} {name} {iq}{suffix};");
@@ -545,7 +545,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Msl
IoVariable.FragmentOutputColor => $"[[color({ioDefinition.Location})]]",
IoVariable.FragmentOutputDepth => "[[depth(any)]]",
IoVariable.ClipDistance => $"[[clip_distance]][{Defaults.TotalClipDistances}]",
_ => string.Empty
_ => ""
};
context.AppendLine($"{type} {name} {suffix};");

View File

@@ -27,7 +27,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Msl.Instructions
inputsCount--;
}
string fieldName = string.Empty;
string fieldName = "";
switch (storageKind)
{
case StorageKind.ConstantBuffer:
@@ -140,7 +140,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Msl.Instructions
}
}
varName += fieldName;
varName += fieldHasPadding ? ".x" : string.Empty;
varName += fieldHasPadding ? ".x" : "";
if (isStore)
{
@@ -434,7 +434,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Msl.Instructions
string prefix = intCoords ? "uint" : "float";
return prefix + (count > 1 ? count : string.Empty) + "(" + coords + ")";
return prefix + (count > 1 ? count : "") + "(" + coords + ")";
}
Append(AssemblePVector(pCount));
@@ -504,7 +504,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Msl.Instructions
}
texCallBuilder.Append(')');
texCallBuilder.Append(colorIsVector ? GetMaskMultiDest(texOp.Index) : string.Empty);
texCallBuilder.Append(colorIsVector ? GetMaskMultiDest(texOp.Index) : "");
return texCallBuilder.ToString();
}
@@ -558,7 +558,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Msl.Instructions
{
if (mask == 0x0)
{
return string.Empty;
return "";
}
string swizzle = ".";

View File

@@ -15,7 +15,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Msl
if (parameters.Definitions.Stage is not (ShaderStage.Vertex or ShaderStage.Fragment or ShaderStage.Compute))
{
Logger.Warning?.Print(LogClass.Gpu, $"Attempted to generate unsupported shader type {parameters.Definitions.Stage}!");
return string.Empty;
return "";
}
CodeGenContext context = new(info, parameters);

View File

@@ -199,7 +199,7 @@ namespace Ryujinx.Graphics.Shader
_ => "float"
};
return $"{typeName}<{format}{(image ? ", access::read_write" : string.Empty)}>";
return $"{typeName}<{format}{(image ? ", access::read_write" : "")}>";
}
}
}

View File

@@ -679,7 +679,7 @@ namespace Ryujinx.HLE.HOS
{
using (MD5 md5 = MD5.Create())
{
modLoadResult.Hash += BitConverter.ToString(md5.ComputeHash(tempHash.ToBytes())).Replace("-", string.Empty).ToLowerInvariant();
modLoadResult.Hash += BitConverter.ToString(md5.ComputeHash(tempHash.ToBytes())).Replace("-", "").ToLowerInvariant();
}
}

View File

@@ -121,7 +121,7 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator.LdnRyu
private void UpdatePassphraseIfNeeded()
{
string passphrase = _config.MultiplayerLdnPassphrase ?? string.Empty;
string passphrase = _config.MultiplayerLdnPassphrase ?? "";
if (passphrase != _passphrase)
{
_passphrase = passphrase;

View File

@@ -88,7 +88,7 @@ namespace Ryujinx.HLE.Loaders.Processes
bool isFirmwareApplication = ProgramId <= 0x0100000000007FFF;
string name = !isFirmware
? (isFirmwareApplication ? "Firmware Application " : string.Empty) + (!string.IsNullOrWhiteSpace(Name) ? Name : "<Unknown Name>")
? (isFirmwareApplication ? "Firmware Application " : "") + (!string.IsNullOrWhiteSpace(Name) ? Name : "<Unknown Name>")
: "Firmware";
// TODO: LibHac npdm currently doesn't support version field.

View File

@@ -7768,7 +7768,7 @@
"th_TH": "",
"tr_TR": "",
"uk_UA": "",
"zh_CN": "颜色",
"zh_CN": "",
"zh_TW": ""
}
},
@@ -19018,7 +19018,7 @@
"th_TH": "",
"tr_TR": "",
"uk_UA": "",
"zh_CN": "LED 设置",
"zh_CN": "",
"zh_TW": ""
}
},

View File

@@ -206,16 +206,6 @@ namespace Ryujinx.Ava
_ => ConfigurationState.Instance.Graphics.GraphicsBackend
};
// Check if backend threading was overridden
if (CommandLineState.OverrideBackendThreading is not null)
ConfigurationState.Instance.Graphics.BackendThreading.Value = CommandLineState.OverrideBackendThreading.ToLower() switch
{
"auto" => BackendThreading.Auto,
"off" => BackendThreading.Off,
"on" => BackendThreading.On,
_ => ConfigurationState.Instance.Graphics.BackendThreading
};
// Check if docked mode was overriden.
if (CommandLineState.OverrideDockedMode.HasValue)
ConfigurationState.Instance.System.EnableDockedMode.Value = CommandLineState.OverrideDockedMode.Value;

View File

@@ -13,6 +13,11 @@
mc:Ignorable="d"
Focusable="True"
x:DataType="viewModels:UserSelectorDialogViewModel">
<UserControl.Resources>
<helpers:BitmapArrayValueConverter x:Key="ByteImage" />
</UserControl.Resources>
<Design.DataContext>
<viewModels:UserSelectorDialogViewModel />
</Design.DataContext>
@@ -75,7 +80,7 @@
Height="96"
HorizontalAlignment="Stretch"
VerticalAlignment="Top"
Source="{Binding Image, Converter={x:Static helpers:BitmapArrayValueConverter.Instance}}" />
Source="{Binding Image, Converter={StaticResource ByteImage}}" />
<TextBlock
HorizontalAlignment="Stretch"
MaxWidth="90"
@@ -105,5 +110,12 @@
</ListBox>
</Border>
<StackPanel
Grid.Row="1"
Margin="0 24 0 0"
HorizontalAlignment="Left"
Orientation="Horizontal"
Spacing="10">
</StackPanel>
</Grid>
</UserControl>

View File

@@ -13,6 +13,9 @@
mc:Ignorable="d"
xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
x:DataType="viewModels:MainWindowViewModel">
<UserControl.Resources>
<helpers:BitmapArrayValueConverter x:Key="ByteImage" />
</UserControl.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
@@ -65,7 +68,7 @@
Grid.Row="0"
HorizontalAlignment="Stretch"
VerticalAlignment="Top"
Source="{Binding Icon, Converter={x:Static helpers:BitmapArrayValueConverter.Instance}}" />
Source="{Binding Icon, Converter={StaticResource ByteImage}}" />
<Panel
Grid.Row="1"
Height="50"

View File

@@ -12,6 +12,9 @@
mc:Ignorable="d"
xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
x:DataType="viewModels:MainWindowViewModel">
<UserControl.Resources>
<helpers:BitmapArrayValueConverter x:Key="ByteImage" />
</UserControl.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
@@ -59,7 +62,7 @@
Classes.large="{Binding $parent[UserControl].((viewModels:MainWindowViewModel)DataContext).IsGridLarge}"
Classes.normal="{Binding $parent[UserControl].((viewModels:MainWindowViewModel)DataContext).IsGridMedium}"
Classes.small="{Binding $parent[UserControl].((viewModels:MainWindowViewModel)DataContext).IsGridSmall}"
Source="{Binding Icon, Converter={x:Static helpers:BitmapArrayValueConverter.Instance}}" />
Source="{Binding Icon, Converter={StaticResource ByteImage}}" />
<Border
Grid.Column="2"
Margin="0,0,5,0"

View File

@@ -9,7 +9,7 @@ namespace Ryujinx.Ava.UI.Helpers
{
internal class BitmapArrayValueConverter : IValueConverter
{
public static readonly BitmapArrayValueConverter Instance = new();
public static BitmapArrayValueConverter Instance = new();
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{

View File

@@ -11,7 +11,7 @@ namespace Ryujinx.Ava.UI.Helpers
{
internal class DownloadableContentLabelConverter : IMultiValueConverter
{
public static readonly DownloadableContentLabelConverter Instance = new();
public static DownloadableContentLabelConverter Instance = new();
public object Convert(IList<object> values, Type targetType, object parameter, CultureInfo culture)
{

View File

@@ -10,7 +10,7 @@ namespace Ryujinx.Ava.UI.Helpers
{
internal class KeyValueConverter : IValueConverter
{
public static readonly KeyValueConverter Instance = new();
public static KeyValueConverter Instance = new();
private static readonly Dictionary<Key, LocaleKeys> _keysMap = new()
{

View File

@@ -1,5 +1,6 @@
using Avalonia.Data.Converters;
using Avalonia.Markup.Xaml;
using Ryujinx.Ava.Common.Locale;
using Ryujinx.Ava.Utilities.AppLibrary;
using System;
using System.Globalization;
@@ -18,10 +19,15 @@ namespace Ryujinx.Ava.UI.Helpers
{
return $"Hosted Games: {applicationData.GameCount}\nOnline Players: {applicationData.PlayerCount}";
}
else
{
return "";
}
}
else
{
return "";
}
return "";
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)

View File

@@ -11,7 +11,7 @@ namespace Ryujinx.Ava.UI.Helpers
{
internal class TitleUpdateLabelConverter : IMultiValueConverter
{
public static readonly TitleUpdateLabelConverter Instance = new();
public static TitleUpdateLabelConverter Instance = new();
public object Convert(IList<object> values, Type targetType, object parameter, CultureInfo culture)
{

View File

@@ -12,7 +12,7 @@ namespace Ryujinx.Ava.UI.Helpers
internal class XCITrimmerFileSpaceSavingsConverter : IValueConverter
{
private const long _bytesPerMB = 1024 * 1024;
public static readonly XCITrimmerFileSpaceSavingsConverter Instance = new();
public static XCITrimmerFileSpaceSavingsConverter Instance = new();
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{

View File

@@ -9,7 +9,7 @@ namespace Ryujinx.Ava.UI.Models
{
private bool _isEnabled = false;
public ObservableCollection<CheatNode> SubNodes { get; } = [];
public string CleanName => Name.Length > 0 ? Name[1..^7] : Name;
public string CleanName => Name[1..^7];
public string BuildIdKey => $"{BuildId}-{Name}";
public bool IsRootNode { get; }
public string Name { get; }

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,6 +3,7 @@ using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using FluentAvalonia.UI.Controls;
using Ryujinx.Ava.UI.Helpers;
using Ryujinx.Ava.Input;
using Ryujinx.Ava.UI.Models.Input;
using Ryujinx.Ava.UI.Views.Input;
using Ryujinx.UI.Views.Input;
@@ -11,8 +12,30 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
{
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;
public bool IsLeft
{
@@ -38,14 +61,15 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
}
public bool HasSides => IsLeft ^ IsRight;
[ObservableProperty] private SvgImage _image;
public InputViewModel ParentModel { get; }
public ControllerInputViewModel(InputViewModel model, GamepadInputConfig config)
public ControllerInputViewModel(InputViewModel model, GamepadInputConfig config, StickVisualizer visualizer)
{
ParentModel = model;
Visualizer = visualizer;
model.NotifyChangesEvent += OnParentModelChanged;
OnParentModelChanged();
Config = config;

View File

@@ -48,7 +48,7 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
private int _controller;
private string _controllerImage;
private int _device;
[ObservableProperty] private object _configViewModel;
private object _configViewModel;
[ObservableProperty] private string _profileName;
private bool _isLoaded;
@@ -67,6 +67,7 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
OnPropertiesChanged(nameof(HasLed), nameof(CanClearLed));
}
}
public StickVisualizer VisualStick { get; private set; }
public ObservableCollection<PlayerModel> PlayerIndexes { get; set; }
public ObservableCollection<(DeviceType Type, string Id, string Name)> Devices { get; set; }
@@ -87,6 +88,19 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
public bool IsModified { get; set; }
public event Action NotifyChangesEvent;
public object ConfigViewModel
{
get => _configViewModel;
set
{
_configViewModel = value;
VisualStick.UpdateConfig(value);
OnPropertyChanged();
}
}
public PlayerIndex PlayerIdChoose
{
get => _playerIdChoose;
@@ -262,6 +276,7 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
Devices = [];
ProfilesList = [];
DeviceList = [];
VisualStick = new StickVisualizer(this);
ControllerImage = ProControllerResource;
@@ -282,12 +297,12 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
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)
{
ConfigViewModel = new ControllerInputViewModel(this, new GamepadInputConfig(controllerInputConfig));
ConfigViewModel = new ControllerInputViewModel(this, new GamepadInputConfig(controllerInputConfig), VisualStick);
}
}
@@ -886,6 +901,8 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
_mainWindow.ViewModel.AppHost?.NpadManager.UnblockInputUpdates();
VisualStick.Dispose();
SelectedGamepad?.Dispose();
AvaloniaKeyboardDriver.Dispose();

View File

@@ -6,7 +6,29 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
{
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;
public bool IsLeft
@@ -38,9 +60,10 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
public readonly InputViewModel ParentModel;
public KeyboardInputViewModel(InputViewModel model, KeyboardInputConfig config)
public KeyboardInputViewModel(InputViewModel model, KeyboardInputConfig config, StickVisualizer visualizer)
{
ParentModel = model;
Visualizer = visualizer;
model.NotifyChangesEvent += OnParentModelChanged;
OnParentModelChanged();
Config = config;

View File

@@ -20,6 +20,9 @@
<Design.DataContext>
<viewModels:ControllerInputViewModel />
</Design.DataContext>
<UserControl.Resources>
<helpers:KeyValueConverter x:Key="Key" />
</UserControl.Resources>
<UserControl.Styles>
<Style Selector="ToggleButton">
<Setter Property="Width" Value="90" />
@@ -75,7 +78,7 @@
TextAlignment="Center" />
<ToggleButton Name="ButtonZl">
<TextBlock
Text="{Binding Config.ButtonZl, Converter={x:Static helpers:KeyValueConverter.Instance}}"
Text="{Binding Config.ButtonZl, Converter={StaticResource Key}}"
TextAlignment="Center" />
</ToggleButton>
</StackPanel>
@@ -91,7 +94,7 @@
TextAlignment="Center" />
<ToggleButton Name="ButtonL">
<TextBlock
Text="{Binding Config.ButtonL, Converter={x:Static helpers:KeyValueConverter.Instance}}"
Text="{Binding Config.ButtonL, Converter={StaticResource Key}}"
TextAlignment="Center" />
</ToggleButton>
</StackPanel>
@@ -107,7 +110,7 @@
TextAlignment="Center" />
<ToggleButton Name="ButtonMinus">
<TextBlock
Text="{Binding Config.ButtonMinus, Converter={x:Static helpers:KeyValueConverter.Instance}}"
Text="{Binding Config.ButtonMinus, Converter={StaticResource Key}}"
TextAlignment="Center" />
</ToggleButton>
</StackPanel>
@@ -141,7 +144,7 @@
TextAlignment="Center" />
<ToggleButton Name="LeftStickButton">
<TextBlock
Text="{Binding Config.LeftStickButton, Converter={x:Static helpers:KeyValueConverter.Instance}}"
Text="{Binding Config.LeftStickButton, Converter={StaticResource Key}}"
TextAlignment="Center" />
</ToggleButton>
</StackPanel>
@@ -158,7 +161,7 @@
TextAlignment="Center" />
<ToggleButton Name="LeftJoystick" Tag="stick">
<TextBlock
Text="{Binding Config.LeftJoystick, Converter={x:Static helpers:KeyValueConverter.Instance}}"
Text="{Binding Config.LeftJoystick, Converter={StaticResource Key}}"
TextAlignment="Center" />
</ToggleButton>
</StackPanel>
@@ -251,7 +254,7 @@
TextAlignment="Center" />
<ToggleButton Name="DpadUp">
<TextBlock
Text="{Binding Config.DpadUp, Converter={x:Static helpers:KeyValueConverter.Instance}}"
Text="{Binding Config.DpadUp, Converter={StaticResource Key}}"
TextAlignment="Center" />
</ToggleButton>
</StackPanel>
@@ -268,7 +271,7 @@
TextAlignment="Center" />
<ToggleButton Name="DpadDown">
<TextBlock
Text="{Binding Config.DpadDown, Converter={x:Static helpers:KeyValueConverter.Instance}}"
Text="{Binding Config.DpadDown, Converter={StaticResource Key}}"
TextAlignment="Center" />
</ToggleButton>
</StackPanel>
@@ -285,7 +288,7 @@
TextAlignment="Center" />
<ToggleButton Name="DpadLeft">
<TextBlock
Text="{Binding Config.DpadLeft, Converter={x:Static helpers:KeyValueConverter.Instance}}"
Text="{Binding Config.DpadLeft, Converter={StaticResource Key}}"
TextAlignment="Center" />
</ToggleButton>
</StackPanel>
@@ -302,7 +305,7 @@
TextAlignment="Center" />
<ToggleButton Name="DpadRight">
<TextBlock
Text="{Binding Config.DpadRight, Converter={x:Static helpers:KeyValueConverter.Instance}}"
Text="{Binding Config.DpadRight, Converter={StaticResource Key}}"
TextAlignment="Center" />
</ToggleButton>
</StackPanel>
@@ -316,17 +319,103 @@
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch">
<!-- Controller Picture -->
<Image
Margin="0,10"
MaxHeight="300"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Source="{Binding Image}" />
<Border
BorderBrush="{DynamicResource ThemeControlBorderColor}"
BorderThickness="1"
CornerRadius="5"
Margin="0,10"
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="{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}" />
<Ellipse
HorizontalAlignment="Center"
Fill="Gray"
Opacity="100"
Height="{Binding Visualizer.UiDeadzoneLeft}"
Width="{Binding Visualizer.UiDeadzoneLeft}" />
</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}" />
<Ellipse
HorizontalAlignment="Center"
Fill="Gray"
Opacity="100"
Height="{Binding Visualizer.UiDeadzoneRight}"
Width="{Binding Visualizer.UiDeadzoneRight}" />
</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>
</StackPanel>
</Border>
<Border
BorderBrush="{DynamicResource ThemeControlBorderColor}"
BorderThickness="1"
CornerRadius="5">
<StackPanel
Margin="8"
Orientation="Vertical">
@@ -345,8 +434,8 @@
Minimum="0"
Value="{Binding Config.TriggerThreshold, Mode=TwoWay}" />
<TextBlock
Width="25"
Text="{Binding Config.TriggerThreshold, StringFormat=\{0:0.00\}}" />
Width="25"
Text="{Binding Config.TriggerThreshold, StringFormat=\{0:0.00\}}" />
</StackPanel>
<StackPanel
Orientation="Vertical"
@@ -365,7 +454,7 @@
TextAlignment="Center" />
<ToggleButton Name="LeftButtonSr">
<TextBlock
Text="{Binding Config.LeftButtonSr, Converter={x:Static helpers:KeyValueConverter.Instance}}"
Text="{Binding Config.LeftButtonSr, Converter={StaticResource Key}}"
TextAlignment="Center" />
</ToggleButton>
</StackPanel>
@@ -383,7 +472,7 @@
TextAlignment="Center" />
<ToggleButton Name="LeftButtonSl">
<TextBlock
Text="{Binding Config.LeftButtonSl, Converter={x:Static helpers:KeyValueConverter.Instance}}"
Text="{Binding Config.LeftButtonSl, Converter={StaticResource Key}}"
TextAlignment="Center" />
</ToggleButton>
</StackPanel>
@@ -401,7 +490,7 @@
TextAlignment="Center" />
<ToggleButton Name="RightButtonSr">
<TextBlock
Text="{Binding Config.RightButtonSr, Converter={x:Static helpers:KeyValueConverter.Instance}}"
Text="{Binding Config.RightButtonSr, Converter={StaticResource Key}}"
TextAlignment="Center" />
</ToggleButton>
</StackPanel>
@@ -419,7 +508,7 @@
TextAlignment="Center" />
<ToggleButton Name="RightButtonSl">
<TextBlock
Text="{Binding Config.RightButtonSl, Converter={x:Static helpers:KeyValueConverter.Instance}}"
Text="{Binding Config.RightButtonSl, Converter={StaticResource Key}}"
TextAlignment="Center" />
</ToggleButton>
</StackPanel>
@@ -547,7 +636,7 @@
TextAlignment="Center" />
<ToggleButton Name="ButtonZr">
<TextBlock
Text="{Binding Config.ButtonZr, Converter={x:Static helpers:KeyValueConverter.Instance}}"
Text="{Binding Config.ButtonZr, Converter={StaticResource Key}}"
TextAlignment="Center" />
</ToggleButton>
</StackPanel>
@@ -565,7 +654,7 @@
TextAlignment="Center" />
<ToggleButton Name="ButtonR">
<TextBlock
Text="{Binding Config.ButtonR, Converter={x:Static helpers:KeyValueConverter.Instance}}"
Text="{Binding Config.ButtonR, Converter={StaticResource Key}}"
TextAlignment="Center" />
</ToggleButton>
</StackPanel>
@@ -583,7 +672,7 @@
TextAlignment="Center" />
<ToggleButton Name="ButtonPlus">
<TextBlock
Text="{Binding Config.ButtonPlus, Converter={x:Static helpers:KeyValueConverter.Instance}}"
Text="{Binding Config.ButtonPlus, Converter={StaticResource Key}}"
TextAlignment="Center" />
</ToggleButton>
</StackPanel>
@@ -618,7 +707,7 @@
TextAlignment="Center" />
<ToggleButton Name="ButtonA">
<TextBlock
Text="{Binding Config.ButtonA, Converter={x:Static helpers:KeyValueConverter.Instance}}"
Text="{Binding Config.ButtonA, Converter={StaticResource Key}}"
TextAlignment="Center" />
</ToggleButton>
</StackPanel>
@@ -635,7 +724,7 @@
TextAlignment="Center" />
<ToggleButton Name="ButtonB">
<TextBlock
Text="{Binding Config.ButtonB, Converter={x:Static helpers:KeyValueConverter.Instance}}"
Text="{Binding Config.ButtonB, Converter={StaticResource Key}}"
TextAlignment="Center" />
</ToggleButton>
</StackPanel>
@@ -652,7 +741,7 @@
TextAlignment="Center" />
<ToggleButton Name="ButtonX">
<TextBlock
Text="{Binding Config.ButtonX, Converter={x:Static helpers:KeyValueConverter.Instance}}"
Text="{Binding Config.ButtonX, Converter={StaticResource Key}}"
TextAlignment="Center" />
</ToggleButton>
</StackPanel>
@@ -669,7 +758,7 @@
TextAlignment="Center" />
<ToggleButton Name="ButtonY">
<TextBlock
Text="{Binding Config.ButtonY, Converter={x:Static helpers:KeyValueConverter.Instance}}"
Text="{Binding Config.ButtonY, Converter={StaticResource Key}}"
TextAlignment="Center" />
</ToggleButton>
</StackPanel>
@@ -703,7 +792,7 @@
TextAlignment="Center" />
<ToggleButton Name="RightStickButton">
<TextBlock
Text="{Binding Config.RightStickButton, Converter={x:Static helpers:KeyValueConverter.Instance}}"
Text="{Binding Config.RightStickButton, Converter={StaticResource Key}}"
TextAlignment="Center" />
</ToggleButton>
</StackPanel>
@@ -721,7 +810,7 @@
TextAlignment="Center" />
<ToggleButton Name="RightJoystick" Tag="stick">
<TextBlock
Text="{Binding Config.RightJoystick, Converter={x:Static helpers:KeyValueConverter.Instance}}"
Text="{Binding Config.RightJoystick, Converter={StaticResource Key}}"
TextAlignment="Center" />
</ToggleButton>
</StackPanel>

View File

@@ -18,6 +18,9 @@
<Design.DataContext>
<viewModels:KeyboardInputViewModel />
</Design.DataContext>
<UserControl.Resources>
<helpers:KeyValueConverter x:Key="Key" />
</UserControl.Resources>
<UserControl.Styles>
<Style Selector="ToggleButton">
<Setter Property="Width" Value="90" />
@@ -73,7 +76,7 @@
TextAlignment="Center" />
<ToggleButton Name="ButtonZl">
<TextBlock
Text="{Binding Config.ButtonZl, Converter={x:Static helpers:KeyValueConverter.Instance}}"
Text="{Binding Config.ButtonZl, Converter={StaticResource Key}}"
TextAlignment="Center" />
</ToggleButton>
</StackPanel>
@@ -89,7 +92,7 @@
TextAlignment="Center" />
<ToggleButton Name="ButtonL">
<TextBlock
Text="{Binding Config.ButtonL, Converter={x:Static helpers:KeyValueConverter.Instance}}"
Text="{Binding Config.ButtonL, Converter={StaticResource Key}}"
TextAlignment="Center" />
</ToggleButton>
</StackPanel>
@@ -105,7 +108,7 @@
TextAlignment="Center" />
<ToggleButton Name="ButtonMinus">
<TextBlock
Text="{Binding Config.ButtonMinus, Converter={x:Static helpers:KeyValueConverter.Instance}}"
Text="{Binding Config.ButtonMinus, Converter={StaticResource Key}}"
TextAlignment="Center" />
</ToggleButton>
</StackPanel>
@@ -140,7 +143,7 @@
TextAlignment="Center" />
<ToggleButton Name="LeftStickButton">
<TextBlock
Text="{Binding Config.LeftStickButton, Converter={x:Static helpers:KeyValueConverter.Instance}}"
Text="{Binding Config.LeftStickButton, Converter={StaticResource Key}}"
TextAlignment="Center" />
</ToggleButton>
</StackPanel>
@@ -157,7 +160,7 @@
TextAlignment="Center" />
<ToggleButton Name="LeftStickUp">
<TextBlock
Text="{Binding Config.LeftStickUp, Converter={x:Static helpers:KeyValueConverter.Instance}}"
Text="{Binding Config.LeftStickUp, Converter={StaticResource Key}}"
TextAlignment="Center" />
</ToggleButton>
</StackPanel>
@@ -174,7 +177,7 @@
TextAlignment="Center" />
<ToggleButton Name="LeftStickDown">
<TextBlock
Text="{Binding Config.LeftStickDown, Converter={x:Static helpers:KeyValueConverter.Instance}}"
Text="{Binding Config.LeftStickDown, Converter={StaticResource Key}}"
TextAlignment="Center" />
</ToggleButton>
</StackPanel>
@@ -191,7 +194,7 @@
TextAlignment="Center" />
<ToggleButton Name="LeftStickLeft">
<TextBlock
Text="{Binding Config.LeftStickLeft, Converter={x:Static helpers:KeyValueConverter.Instance}}"
Text="{Binding Config.LeftStickLeft, Converter={StaticResource Key}}"
TextAlignment="Center" />
</ToggleButton>
</StackPanel>
@@ -208,7 +211,7 @@
TextAlignment="Center" />
<ToggleButton Name="LeftStickRight">
<TextBlock
Text="{Binding Config.LeftStickRight, Converter={x:Static helpers:KeyValueConverter.Instance}}"
Text="{Binding Config.LeftStickRight, Converter={StaticResource Key}}"
TextAlignment="Center" />
</ToggleButton>
</StackPanel>
@@ -244,7 +247,7 @@
TextAlignment="Center" />
<ToggleButton Name="DpadUp">
<TextBlock
Text="{Binding Config.DpadUp, Converter={x:Static helpers:KeyValueConverter.Instance}}"
Text="{Binding Config.DpadUp, Converter={StaticResource Key}}"
TextAlignment="Center" />
</ToggleButton>
</StackPanel>
@@ -261,7 +264,7 @@
TextAlignment="Center" />
<ToggleButton Name="DpadDown">
<TextBlock
Text="{Binding Config.DpadDown, Converter={x:Static helpers:KeyValueConverter.Instance}}"
Text="{Binding Config.DpadDown, Converter={StaticResource Key}}"
TextAlignment="Center" />
</ToggleButton>
</StackPanel>
@@ -278,7 +281,7 @@
TextAlignment="Center" />
<ToggleButton Name="DpadLeft">
<TextBlock
Text="{Binding Config.DpadLeft, Converter={x:Static helpers:KeyValueConverter.Instance}}"
Text="{Binding Config.DpadLeft, Converter={StaticResource Key}}"
TextAlignment="Center" />
</ToggleButton>
</StackPanel>
@@ -295,7 +298,7 @@
TextAlignment="Center" />
<ToggleButton Name="DpadRight">
<TextBlock
Text="{Binding Config.DpadRight, Converter={x:Static helpers:KeyValueConverter.Instance}}"
Text="{Binding Config.DpadRight, Converter={StaticResource Key}}"
TextAlignment="Center" />
</ToggleButton>
</StackPanel>
@@ -309,12 +312,79 @@
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch">
<!-- Controller Picture -->
<Image
<Border
BorderBrush="{DynamicResource ThemeControlBorderColor}"
BorderThickness="1"
CornerRadius="5"
Margin="0,10"
MaxHeight="300"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Source="{Binding Image}" />
MinHeight="90">
<StackPanel
Margin="10"
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
BorderBrush="{DynamicResource ThemeControlBorderColor}"
BorderThickness="1"
@@ -338,7 +408,7 @@
TextAlignment="Center" />
<ToggleButton Name="LeftButtonSr">
<TextBlock
Text="{Binding Config.LeftButtonSr, Converter={x:Static helpers:KeyValueConverter.Instance}}"
Text="{Binding Config.LeftButtonSr, Converter={StaticResource Key}}"
TextAlignment="Center" />
</ToggleButton>
</StackPanel>
@@ -356,7 +426,7 @@
TextAlignment="Center" />
<ToggleButton Name="LeftButtonSl">
<TextBlock
Text="{Binding Config.LeftButtonSl, Converter={x:Static helpers:KeyValueConverter.Instance}}"
Text="{Binding Config.LeftButtonSl, Converter={StaticResource Key}}"
TextAlignment="Center" />
</ToggleButton>
</StackPanel>
@@ -374,7 +444,7 @@
TextAlignment="Center" />
<ToggleButton Name="RightButtonSr">
<TextBlock
Text="{Binding Config.RightButtonSr, Converter={x:Static helpers:KeyValueConverter.Instance}}"
Text="{Binding Config.RightButtonSr, Converter={StaticResource Key}}"
TextAlignment="Center" />
</ToggleButton>
</StackPanel>
@@ -392,7 +462,7 @@
TextAlignment="Center" />
<ToggleButton Name="RightButtonSl">
<TextBlock
Text="{Binding Config.RightButtonSl, Converter={x:Static helpers:KeyValueConverter.Instance}}"
Text="{Binding Config.RightButtonSl, Converter={StaticResource Key}}"
TextAlignment="Center" />
</ToggleButton>
</StackPanel>
@@ -434,7 +504,7 @@
TextAlignment="Center" />
<ToggleButton Name="ButtonZr">
<TextBlock
Text="{Binding Config.ButtonZr, Converter={x:Static helpers:KeyValueConverter.Instance}}"
Text="{Binding Config.ButtonZr, Converter={StaticResource Key}}"
TextAlignment="Center" />
</ToggleButton>
</StackPanel>
@@ -452,7 +522,7 @@
TextAlignment="Center" />
<ToggleButton Name="ButtonR">
<TextBlock
Text="{Binding Config.ButtonR, Converter={x:Static helpers:KeyValueConverter.Instance}}"
Text="{Binding Config.ButtonR, Converter={StaticResource Key}}"
TextAlignment="Center" />
</ToggleButton>
</StackPanel>
@@ -470,7 +540,7 @@
TextAlignment="Center" />
<ToggleButton Name="ButtonPlus">
<TextBlock
Text="{Binding Config.ButtonPlus, Converter={x:Static helpers:KeyValueConverter.Instance}}"
Text="{Binding Config.ButtonPlus, Converter={StaticResource Key}}"
TextAlignment="Center" />
</ToggleButton>
</StackPanel>
@@ -505,7 +575,7 @@
TextAlignment="Center" />
<ToggleButton Name="ButtonA">
<TextBlock
Text="{Binding Config.ButtonA, Converter={x:Static helpers:KeyValueConverter.Instance}}"
Text="{Binding Config.ButtonA, Converter={StaticResource Key}}"
TextAlignment="Center" />
</ToggleButton>
</StackPanel>
@@ -522,7 +592,7 @@
TextAlignment="Center" />
<ToggleButton Name="ButtonB">
<TextBlock
Text="{Binding Config.ButtonB, Converter={x:Static helpers:KeyValueConverter.Instance}}"
Text="{Binding Config.ButtonB, Converter={StaticResource Key}}"
TextAlignment="Center" />
</ToggleButton>
</StackPanel>
@@ -539,7 +609,7 @@
TextAlignment="Center" />
<ToggleButton Name="ButtonX">
<TextBlock
Text="{Binding Config.ButtonX, Converter={x:Static helpers:KeyValueConverter.Instance}}"
Text="{Binding Config.ButtonX, Converter={StaticResource Key}}"
TextAlignment="Center" />
</ToggleButton>
</StackPanel>
@@ -556,7 +626,7 @@
TextAlignment="Center" />
<ToggleButton Name="ButtonY">
<TextBlock
Text="{Binding Config.ButtonY, Converter={x:Static helpers:KeyValueConverter.Instance}}"
Text="{Binding Config.ButtonY, Converter={StaticResource Key}}"
TextAlignment="Center" />
</ToggleButton>
</StackPanel>
@@ -591,7 +661,7 @@
TextAlignment="Center" />
<ToggleButton Name="RightStickButton">
<TextBlock
Text="{Binding Config.RightStickButton, Converter={x:Static helpers:KeyValueConverter.Instance}}"
Text="{Binding Config.RightStickButton, Converter={StaticResource Key}}"
TextAlignment="Center" />
</ToggleButton>
</StackPanel>
@@ -608,7 +678,7 @@
TextAlignment="Center" />
<ToggleButton Name="RightStickUp">
<TextBlock
Text="{Binding Config.RightStickUp, Converter={x:Static helpers:KeyValueConverter.Instance}}"
Text="{Binding Config.RightStickUp, Converter={StaticResource Key}}"
TextAlignment="Center" />
</ToggleButton>
</StackPanel>
@@ -625,7 +695,7 @@
TextAlignment="Center" />
<ToggleButton Name="RightStickDown">
<TextBlock
Text="{Binding Config.RightStickDown, Converter={x:Static helpers:KeyValueConverter.Instance}}"
Text="{Binding Config.RightStickDown, Converter={StaticResource Key}}"
TextAlignment="Center" />
</ToggleButton>
</StackPanel>
@@ -642,7 +712,7 @@
TextAlignment="Center" />
<ToggleButton Name="RightStickLeft">
<TextBlock
Text="{Binding Config.RightStickLeft, Converter={x:Static helpers:KeyValueConverter.Instance}}"
Text="{Binding Config.RightStickLeft, Converter={StaticResource Key}}"
TextAlignment="Center" />
</ToggleButton>
</StackPanel>
@@ -659,7 +729,7 @@
TextAlignment="Center" />
<ToggleButton Name="RightStickRight">
<TextBlock
Text="{Binding Config.RightStickRight, Converter={x:Static helpers:KeyValueConverter.Instance}}"
Text="{Binding Config.RightStickRight, Converter={StaticResource Key}}"
TextAlignment="Center" />
</ToggleButton>
</StackPanel>

View File

@@ -14,6 +14,9 @@
<Design.DataContext>
<viewModels:SettingsViewModel />
</Design.DataContext>
<UserControl.Resources>
<helpers:KeyValueConverter x:Key="Key" />
</UserControl.Resources>
<UserControl.Styles>
<Style Selector="StackPanel > StackPanel">
<Setter Property="Margin" Value="10, 0, 0, 0" />
@@ -49,67 +52,67 @@
<StackPanel>
<TextBlock Text="{ext:Locale SettingsTabHotkeysToggleVSyncModeHotkey}" />
<ToggleButton Name="ToggleVSyncMode">
<TextBlock Text="{Binding KeyboardHotkey.ToggleVSyncMode, Converter={x:Static helpers:KeyValueConverter.Instance}}" />
<TextBlock Text="{Binding KeyboardHotkey.ToggleVSyncMode, Converter={StaticResource Key}}" />
</ToggleButton>
</StackPanel>
<StackPanel>
<TextBlock Text="{ext:Locale SettingsTabHotkeysScreenshotHotkey}" />
<ToggleButton Name="Screenshot">
<TextBlock Text="{Binding KeyboardHotkey.Screenshot, Converter={x:Static helpers:KeyValueConverter.Instance}}" />
<TextBlock Text="{Binding KeyboardHotkey.Screenshot, Converter={StaticResource Key}}" />
</ToggleButton>
</StackPanel>
<StackPanel>
<TextBlock Text="{ext:Locale SettingsTabHotkeysShowUiHotkey}" />
<ToggleButton Name="ShowUI">
<TextBlock Text="{Binding KeyboardHotkey.ShowUI, Converter={x:Static helpers:KeyValueConverter.Instance}}" />
<TextBlock Text="{Binding KeyboardHotkey.ShowUI, Converter={StaticResource Key}}" />
</ToggleButton>
</StackPanel>
<StackPanel>
<TextBlock Text="{ext:Locale SettingsTabHotkeysPauseHotkey}" />
<ToggleButton Name="Pause">
<TextBlock Text="{Binding KeyboardHotkey.Pause, Converter={x:Static helpers:KeyValueConverter.Instance}}" />
<TextBlock Text="{Binding KeyboardHotkey.Pause, Converter={StaticResource Key}}" />
</ToggleButton>
</StackPanel>
<StackPanel>
<TextBlock Text="{ext:Locale SettingsTabHotkeysToggleMuteHotkey}" />
<ToggleButton Name="ToggleMute">
<TextBlock Text="{Binding KeyboardHotkey.ToggleMute, Converter={x:Static helpers:KeyValueConverter.Instance}}" />
<TextBlock Text="{Binding KeyboardHotkey.ToggleMute, Converter={StaticResource Key}}" />
</ToggleButton>
</StackPanel>
<StackPanel>
<TextBlock Text="{ext:Locale SettingsTabHotkeysResScaleUpHotkey}" />
<ToggleButton Name="ResScaleUp">
<TextBlock Text="{Binding KeyboardHotkey.ResScaleUp, Converter={x:Static helpers:KeyValueConverter.Instance}}" />
<TextBlock Text="{Binding KeyboardHotkey.ResScaleUp, Converter={StaticResource Key}}" />
</ToggleButton>
</StackPanel>
<StackPanel>
<TextBlock Text="{ext:Locale SettingsTabHotkeysResScaleDownHotkey}" />
<ToggleButton Name="ResScaleDown">
<TextBlock Text="{Binding KeyboardHotkey.ResScaleDown, Converter={x:Static helpers:KeyValueConverter.Instance}}" />
<TextBlock Text="{Binding KeyboardHotkey.ResScaleDown, Converter={StaticResource Key}}" />
</ToggleButton>
</StackPanel>
<StackPanel>
<TextBlock Text="{ext:Locale SettingsTabHotkeysVolumeUpHotkey}" />
<ToggleButton Name="VolumeUp">
<TextBlock Text="{Binding KeyboardHotkey.VolumeUp, Converter={x:Static helpers:KeyValueConverter.Instance}}" />
<TextBlock Text="{Binding KeyboardHotkey.VolumeUp, Converter={StaticResource Key}}" />
</ToggleButton>
</StackPanel>
<StackPanel>
<TextBlock Text="{ext:Locale SettingsTabHotkeysVolumeDownHotkey}" />
<ToggleButton Name="VolumeDown">
<TextBlock Text="{Binding KeyboardHotkey.VolumeDown, Converter={x:Static helpers:KeyValueConverter.Instance}}" />
<TextBlock Text="{Binding KeyboardHotkey.VolumeDown, Converter={StaticResource Key}}" />
</ToggleButton>
</StackPanel>
<StackPanel Margin="10,0,0,0" Orientation="Horizontal">
<TextBlock Text="{ext:Locale SettingsTabHotkeysIncrementCustomVSyncIntervalHotkey}" />
<ToggleButton Name="CustomVSyncIntervalIncrement">
<TextBlock Text="{Binding KeyboardHotkey.CustomVSyncIntervalIncrement, Converter={x:Static helpers:KeyValueConverter.Instance}}" />
<TextBlock Text="{Binding KeyboardHotkey.CustomVSyncIntervalIncrement, Converter={StaticResource Key}}" />
</ToggleButton>
</StackPanel>
<StackPanel Margin="10,0,0,0" Orientation="Horizontal">
<TextBlock Text="{ext:Locale SettingsTabHotkeysDecrementCustomVSyncIntervalHotkey}" />
<ToggleButton Name="CustomVSyncIntervalDecrement">
<TextBlock Text="{Binding KeyboardHotkey.CustomVSyncIntervalDecrement, Converter={x:Static helpers:KeyValueConverter.Instance}}" />
<TextBlock Text="{Binding KeyboardHotkey.CustomVSyncIntervalDecrement, Converter={StaticResource Key}}" />
</ToggleButton>
</StackPanel>
</StackPanel>

View File

@@ -7,26 +7,23 @@ namespace Ryujinx.Ava.UI.Views.Settings
{
public partial class SettingsNetworkView : UserControl
{
private readonly Random _random;
public SettingsViewModel ViewModel;
public SettingsNetworkView()
{
_random = new Random();
InitializeComponent();
}
private void GenLdnPassButton_OnClick(object sender, RoutedEventArgs e)
{
byte[] code = new byte[4];
_random.NextBytes(code);
new Random().NextBytes(code);
ViewModel.LdnPassphrase = $"Ryujinx-{BitConverter.ToUInt32(code):x8}";
}
private void ClearLdnPassButton_OnClick(object sender, RoutedEventArgs e)
{
ViewModel.LdnPassphrase = string.Empty;
ViewModel.LdnPassphrase = "";
}
}
}

View File

@@ -10,6 +10,9 @@
xmlns:helpers="clr-namespace:Ryujinx.Ava.UI.Helpers"
mc:Ignorable="d"
x:DataType="viewModels:SettingsViewModel">
<UserControl.Resources>
<helpers:TimeZoneConverter x:Key="TimeZone" />
</UserControl.Resources>
<Design.DataContext>
<viewModels:SettingsViewModel />
</Design.DataContext>
@@ -159,7 +162,7 @@
Text="{Binding Path=TimeZone, Mode=OneWay}"
TextChanged="TimeZoneBox_OnTextChanged"
ToolTip.Tip="{ext:Locale TimezoneTooltip}"
ValueMemberBinding="{Binding Mode=OneWay, Converter={x:Static helpers:TimeZoneConverter.Instance}}" />
ValueMemberBinding="{Binding Mode=OneWay, Converter={StaticResource TimeZone}}" />
</StackPanel>
<StackPanel
Margin="0,0,0,10"

View File

@@ -14,6 +14,9 @@
mc:Ignorable="d"
Focusable="True"
x:DataType="models:TempProfile">
<UserControl.Resources>
<helpers:BitmapArrayValueConverter x:Key="ByteImage" />
</UserControl.Resources>
<Grid Margin="0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
@@ -71,7 +74,7 @@
Margin="0"
HorizontalAlignment="Stretch"
VerticalAlignment="Top"
Source="{Binding Image, Converter={x:Static helpers:BitmapArrayValueConverter.Instance}}" />
Source="{Binding Image, Converter={StaticResource ByteImage}}" />
</Panel>
</Border>
</StackPanel>

View File

@@ -17,6 +17,9 @@
<Design.DataContext>
<viewModels:UserFirmwareAvatarSelectorViewModel />
</Design.DataContext>
<UserControl.Resources>
<helpers:BitmapArrayValueConverter x:Key="ByteImage" />
</UserControl.Resources>
<Grid
Margin="0"
HorizontalAlignment="Stretch"
@@ -59,7 +62,7 @@
<Panel
Background="{Binding BackgroundColor}"
Margin="5">
<Image Source="{Binding Data, Converter={x:Static helpers:BitmapArrayValueConverter.Instance}}" />
<Image Source="{Binding Data, Converter={StaticResource ByteImage}}" />
</Panel>
</DataTemplate>
</ListBox.ItemTemplate>

View File

@@ -19,6 +19,9 @@
<Design.DataContext>
<viewModels:UserSaveManagerViewModel />
</Design.DataContext>
<UserControl.Resources>
<helpers:BitmapArrayValueConverter x:Key="ByteImage" />
</UserControl.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
@@ -144,7 +147,7 @@
IsVisible="{Binding InGameList}"
Width="42"
Height="42"
Source="{Binding Icon, Converter={x:Static helpers:BitmapArrayValueConverter.Instance}}" />
Source="{Binding Icon, Converter={StaticResource ByteImage}}" />
<TextBlock
MaxLines="3"
Width="320"

View File

@@ -15,6 +15,9 @@
mc:Ignorable="d"
Focusable="True"
x:DataType="viewModels:UserProfileViewModel">
<UserControl.Resources>
<helpers:BitmapArrayValueConverter x:Key="ByteImage" />
</UserControl.Resources>
<Design.DataContext>
<viewModels:UserProfileViewModel />
</Design.DataContext>
@@ -71,7 +74,7 @@
Height="96"
HorizontalAlignment="Stretch"
VerticalAlignment="Top"
Source="{Binding Image, Converter={x:Static helpers:BitmapArrayValueConverter.Instance}}" />
Source="{Binding Image, Converter={StaticResource ByteImage}}" />
<TextBlock
HorizontalAlignment="Stretch"
MaxWidth="90"

View File

@@ -6,8 +6,8 @@
xmlns:ext="clr-namespace:Ryujinx.Ava.Common.Markup"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:window="clr-namespace:Ryujinx.Ava.UI.Windows"
Width="600"
Height="750"
Width="500"
Height="500"
MinWidth="500"
MinHeight="500"
x:DataType="window:CheatWindow"

View File

@@ -34,9 +34,6 @@ namespace Ryujinx.Ava.UI.Windows
public CheatWindow(VirtualFileSystem virtualFileSystem, string titleId, string titleName, string titlePath)
{
MinWidth = 500;
MinHeight = 650;
LoadedCheats = [];
IntegrityCheckLevel checkLevel = ConfigurationState.Instance.System.EnableFsIntegrityChecks
? IntegrityCheckLevel.ErrorOnInvalid

View File

@@ -30,6 +30,9 @@
<Design.DataContext>
<viewModels:MainWindowViewModel />
</Design.DataContext>
<Window.Resources>
<helpers:BitmapArrayValueConverter x:Key="ByteImage" />
</Window.Resources>
<Window.KeyBindings>
<KeyBinding Gesture="Alt+Return" Command="{Binding ToggleFullscreen}" />
<KeyBinding Gesture="F11" Command="{Binding ToggleFullscreen}" />
@@ -118,7 +121,7 @@
Width="256"
Height="256"
IsVisible="{Binding ShowLoadProgress}"
Source="{Binding SelectedIcon, Converter={x:Static helpers:BitmapArrayValueConverter.Instance}}" />
Source="{Binding SelectedIcon, Converter={StaticResource ByteImage}}" />
</Border>
<Grid
Grid.Column="1"

View File

@@ -11,7 +11,7 @@
xmlns:settings="clr-namespace:Ryujinx.Ava.UI.Views.Settings"
xmlns:helpers="clr-namespace:Ryujinx.Ava.UI.Helpers"
Width="1100"
Height="768"
Height="850"
MinWidth="800"
MinHeight="480"
WindowStartupLocation="CenterOwner"

View File

@@ -14,6 +14,9 @@
mc:Ignorable="d"
x:DataType="viewModels:TitleUpdateViewModel"
Focusable="True">
<UserControl.Resources>
<helpers:TitleUpdateLabelConverter x:Key="TitleUpdateLabel" />
</UserControl.Resources>
<Grid RowDefinitions="Auto,*,Auto">
<StackPanel
Grid.Row="0"
@@ -54,7 +57,7 @@
VerticalAlignment="Center"
TextWrapping="Wrap">
<TextBlock.Text>
<MultiBinding Converter="{x:Static helpers:TitleUpdateLabelConverter.Instance}">
<MultiBinding Converter="{StaticResource TitleUpdateLabel}">
<Binding Path="DisplayVersion" />
<Binding Path="IsBundled" />
</MultiBinding>

View File

@@ -13,6 +13,11 @@
x:DataType="viewModels:XCITrimmerViewModel"
Focusable="True"
mc:Ignorable="d">
<UserControl.Resources>
<helpers:XCITrimmerFileStatusConverter x:Key="StatusLabel" />
<helpers:XCITrimmerFileStatusDetailConverter x:Key="StatusDetailLabel" />
<helpers:XCITrimmerFileSpaceSavingsConverter x:Key="SpaceSavingsLabel" />
</UserControl.Resources>
<Grid Margin="20 0 20 0">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
@@ -181,7 +186,7 @@
HorizontalAlignment="Left"
VerticalAlignment="Center"
MaxLines="1"
Text="{Binding ., Converter={x:Static helpers:XCITrimmerFileStatusConverter.Instance}}">
Text="{Binding ., Converter={StaticResource StatusLabel}}">
<ToolTip.Tip>
<StackPanel
IsVisible="{Binding IsFailed}">
@@ -189,7 +194,7 @@
Classes="h1"
Text="{ext:Locale XCITrimmerTitleStatusFailed}" />
<TextBlock
Text="{Binding ., Converter={x:Static helpers:XCITrimmerFileStatusDetailConverter.Instance}}"
Text="{Binding ., Converter={StaticResource StatusDetailLabel}}"
MaxLines="5"
MaxWidth="200"
MaxHeight="100"
@@ -204,7 +209,7 @@
HorizontalAlignment="Left"
VerticalAlignment="Center"
MaxLines="1"
Text="{Binding ., Converter={x:Static helpers:XCITrimmerFileSpaceSavingsConverter.Instance}}">>
Text="{Binding ., Converter={StaticResource SpaceSavingsLabel}}">>
</TextBlock>
</Grid>
</Grid>

View File

@@ -10,7 +10,6 @@ namespace Ryujinx.Ava.Utilities
public static bool? OverrideDockedMode { get; private set; }
public static bool? OverrideHardwareAcceleration { get; private set; }
public static string OverrideGraphicsBackend { get; private set; }
public static string OverrideBackendThreading { get; private set; }
public static string OverrideHideCursor { get; private set; }
public static string BaseDirPathArg { get; private set; }
public static string Profile { get; private set; }
@@ -75,16 +74,6 @@ namespace Ryujinx.Ava.Utilities
OverrideGraphicsBackend = args[++i];
break;
case "--backend-threading":
if (i + 1 >= args.Length)
{
Logger.Error?.Print(LogClass.Application, $"Invalid option '{arg}'");
continue;
}
OverrideBackendThreading = args[++i];
break;
case "-i":
case "--application-id":
LaunchApplicationId = args[++i];

View File

@@ -204,8 +204,8 @@ namespace Ryujinx.Ava.Utilities.Configuration
Multiplayer.LanInterfaceId.Value = "0";
Multiplayer.Mode.Value = MultiplayerMode.Disabled;
Multiplayer.DisableP2p.Value = false;
Multiplayer.LdnPassphrase.Value = string.Empty;
Multiplayer.LdnServer.Value = string.Empty;
Multiplayer.LdnPassphrase.Value = "";
Multiplayer.LdnServer.Value = "";
UI.GuiColumns.FavColumn.Value = true;
UI.GuiColumns.IconColumn.Value = true;
UI.GuiColumns.AppColumn.Value = true;