Compare commits
18 Commits
Canary-1.2
...
66ceecd493
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
66ceecd493 | ||
|
|
31de0bf8c6 | ||
|
|
849fd0199e | ||
|
|
f3942968f9 | ||
|
|
57e26114e8 | ||
|
|
6a283190b3 | ||
|
|
85547874c8 | ||
|
|
16ca8e5005 | ||
|
|
cfa5ad0757 | ||
|
|
43ece083b2 | ||
|
|
e1f5c501b0 | ||
|
|
ffe366d953 | ||
|
|
75c7a29278 | ||
|
|
3a0d9c1435 | ||
|
|
93d1476a2a | ||
|
|
ce13830063 | ||
|
|
aa3f2824e0 | ||
|
|
d2bb580aea |
@@ -113,7 +113,7 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator.LdnRyu.Proxy
|
|||||||
public async Task<ushort> NatPunch()
|
public async Task<ushort> NatPunch()
|
||||||
{
|
{
|
||||||
NatDiscoverer discoverer = new();
|
NatDiscoverer discoverer = new();
|
||||||
CancellationTokenSource cts = new(1000);
|
CancellationTokenSource cts = new(5000);
|
||||||
|
|
||||||
NatDevice device;
|
NatDevice device;
|
||||||
|
|
||||||
|
|||||||
@@ -7623,7 +7623,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ID": "ControllerSettingsLedColor",
|
"ID": "ControllerSettingsLed",
|
||||||
"Translations": {
|
"Translations": {
|
||||||
"ar_SA": "",
|
"ar_SA": "",
|
||||||
"de_DE": "",
|
"de_DE": "",
|
||||||
@@ -7697,6 +7697,31 @@
|
|||||||
"zh_TW": ""
|
"zh_TW": ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"ID": "ControllerSettingsLedColor",
|
||||||
|
"Translations": {
|
||||||
|
"ar_SA": "",
|
||||||
|
"de_DE": "",
|
||||||
|
"el_GR": "",
|
||||||
|
"en_US": "Color",
|
||||||
|
"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": "ControllerSettingsSave",
|
"ID": "ControllerSettingsSave",
|
||||||
"Translations": {
|
"Translations": {
|
||||||
@@ -18897,6 +18922,31 @@
|
|||||||
"zh_TW": "震動設定"
|
"zh_TW": "震動設定"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"ID": "ControllerLedTitle",
|
||||||
|
"Translations": {
|
||||||
|
"ar_SA": "",
|
||||||
|
"de_DE": "",
|
||||||
|
"el_GR": "",
|
||||||
|
"en_US": "LED Settings",
|
||||||
|
"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": "SettingsSelectThemeFileDialogTitle",
|
"ID": "SettingsSelectThemeFileDialogTitle",
|
||||||
"Translations": {
|
"Translations": {
|
||||||
|
|||||||
260
src/Ryujinx/UI/Models/Input/StickVisualizer.cs
Normal file
260
src/Ryujinx/UI/Models/Input/StickVisualizer.cs
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,15 +3,39 @@ using CommunityToolkit.Mvvm.ComponentModel;
|
|||||||
using CommunityToolkit.Mvvm.Input;
|
using CommunityToolkit.Mvvm.Input;
|
||||||
using FluentAvalonia.UI.Controls;
|
using FluentAvalonia.UI.Controls;
|
||||||
using Ryujinx.Ava.UI.Helpers;
|
using Ryujinx.Ava.UI.Helpers;
|
||||||
|
using Ryujinx.Ava.Input;
|
||||||
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.UI.Views.Input;
|
||||||
|
|
||||||
namespace Ryujinx.Ava.UI.ViewModels.Input
|
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 +61,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 = config;
|
Config = config;
|
||||||
@@ -59,16 +84,11 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
|
|||||||
{
|
{
|
||||||
await RumbleInputView.Show(this);
|
await RumbleInputView.Show(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public RelayCommand LedDisabledChanged => Commands.Create(() =>
|
public async void ShowLedConfig()
|
||||||
{
|
{
|
||||||
if (!Config.EnableLedChanging) return;
|
await LedInputView.Show(this);
|
||||||
|
}
|
||||||
if (Config.TurnOffLed)
|
|
||||||
ParentModel.SelectedGamepad.ClearLed();
|
|
||||||
else
|
|
||||||
ParentModel.SelectedGamepad.SetLed(Config.LedColor.ToUInt32());
|
|
||||||
});
|
|
||||||
|
|
||||||
public void OnParentModelChanged()
|
public void OnParentModelChanged()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -48,7 +48,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;
|
||||||
|
|
||||||
@@ -67,6 +67,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; }
|
||||||
@@ -87,6 +88,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;
|
||||||
@@ -262,6 +276,7 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
|
|||||||
Devices = [];
|
Devices = [];
|
||||||
ProfilesList = [];
|
ProfilesList = [];
|
||||||
DeviceList = [];
|
DeviceList = [];
|
||||||
|
VisualStick = new StickVisualizer(this);
|
||||||
|
|
||||||
ControllerImage = ProControllerResource;
|
ControllerImage = ProControllerResource;
|
||||||
|
|
||||||
@@ -282,12 +297,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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -886,6 +901,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();
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
53
src/Ryujinx/UI/ViewModels/Input/LedInputViewModel.cs
Normal file
53
src/Ryujinx/UI/ViewModels/Input/LedInputViewModel.cs
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
using Avalonia.Media;
|
||||||
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
|
using CommunityToolkit.Mvvm.Input;
|
||||||
|
using Ryujinx.Ava.UI.Helpers;
|
||||||
|
|
||||||
|
namespace Ryujinx.Ava.UI.ViewModels.Input
|
||||||
|
{
|
||||||
|
public partial class LedInputViewModel : BaseModel
|
||||||
|
{
|
||||||
|
public required InputViewModel ParentModel { get; init; }
|
||||||
|
|
||||||
|
public RelayCommand LedDisabledChanged => Commands.Create(() =>
|
||||||
|
{
|
||||||
|
if (!EnableLedChanging) return;
|
||||||
|
|
||||||
|
if (TurnOffLed)
|
||||||
|
ParentModel.SelectedGamepad.ClearLed();
|
||||||
|
else
|
||||||
|
ParentModel.SelectedGamepad.SetLed(LedColor.ToUInt32());
|
||||||
|
});
|
||||||
|
|
||||||
|
[ObservableProperty] private bool _enableLedChanging;
|
||||||
|
[ObservableProperty] private Color _ledColor;
|
||||||
|
|
||||||
|
public bool ShowLedColorPicker => !TurnOffLed && !UseRainbowLed;
|
||||||
|
|
||||||
|
private bool _turnOffLed;
|
||||||
|
|
||||||
|
public bool TurnOffLed
|
||||||
|
{
|
||||||
|
get => _turnOffLed;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_turnOffLed = value;
|
||||||
|
OnPropertyChanged();
|
||||||
|
OnPropertyChanged(nameof(ShowLedColorPicker));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool _useRainbowLed;
|
||||||
|
|
||||||
|
public bool UseRainbowLed
|
||||||
|
{
|
||||||
|
get => _useRainbowLed;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_useRainbowLed = value;
|
||||||
|
OnPropertyChanged();
|
||||||
|
OnPropertyChanged(nameof(ShowLedColorPicker));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -319,17 +319,103 @@
|
|||||||
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,10"
|
||||||
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="{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
|
<StackPanel
|
||||||
Margin="8"
|
Margin="8"
|
||||||
Orientation="Vertical">
|
Orientation="Vertical">
|
||||||
@@ -348,8 +434,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"
|
||||||
@@ -495,8 +581,6 @@
|
|||||||
Margin="0,-1,0,0">
|
Margin="0,-1,0,0">
|
||||||
<Grid IsVisible="{Binding ParentModel.HasLed}">
|
<Grid IsVisible="{Binding ParentModel.HasLed}">
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="Auto" />
|
|
||||||
<ColumnDefinition Width="*" />
|
|
||||||
<ColumnDefinition Width="*" />
|
<ColumnDefinition Width="*" />
|
||||||
<ColumnDefinition Width="Auto" />
|
<ColumnDefinition Width="Auto" />
|
||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
@@ -505,39 +589,14 @@
|
|||||||
MinWidth="0"
|
MinWidth="0"
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
IsChecked="{Binding Config.EnableLedChanging, Mode=TwoWay}">
|
IsChecked="{Binding Config.EnableLedChanging, Mode=TwoWay}">
|
||||||
<TextBlock Text="{ext:Locale ControllerSettingsLedColor}" />
|
<TextBlock Text="{ext:Locale ControllerSettingsLed}" />
|
||||||
</CheckBox>
|
</CheckBox>
|
||||||
<CheckBox
|
<Button
|
||||||
Margin="5, 10, 5, 10"
|
Margin="10"
|
||||||
MinWidth="0"
|
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
IsVisible="{Binding ParentModel.CanClearLed}"
|
Command="{Binding ShowLedConfig}">
|
||||||
IsChecked="{Binding Config.TurnOffLed, Mode=TwoWay}"
|
<TextBlock Text="{ext:Locale ControllerSettingsConfigureGeneral}" />
|
||||||
Command="{Binding LedDisabledChanged}">
|
</Button>
|
||||||
<TextBlock Text="{ext:Locale ControllerSettingsLedColorDisable}" />
|
|
||||||
</CheckBox>
|
|
||||||
<CheckBox
|
|
||||||
Margin="5, 10 5,10"
|
|
||||||
MinWidth="0"
|
|
||||||
Grid.Column="2"
|
|
||||||
IsEnabled="{Binding !Config.TurnOffLed}"
|
|
||||||
IsChecked="{Binding Config.UseRainbowLed, Mode=TwoWay}">
|
|
||||||
<TextBlock Text="{ext:Locale ControllerSettingsLedColorRainbow}" />
|
|
||||||
</CheckBox>
|
|
||||||
<ui:ColorPickerButton
|
|
||||||
Grid.Column="3"
|
|
||||||
IsEnabled="{Binding Config.ShowLedColorPicker}"
|
|
||||||
Margin="5, 10, 10, 10"
|
|
||||||
IsMoreButtonVisible="False"
|
|
||||||
UseColorPalette="False"
|
|
||||||
UseColorTriangle="False"
|
|
||||||
UseColorWheel="False"
|
|
||||||
ShowAcceptDismissButtons="False"
|
|
||||||
IsAlphaEnabled="False"
|
|
||||||
AttachedToVisualTree="ColorPickerButton_OnAttachedToVisualTree"
|
|
||||||
ColorChanged="ColorPickerButton_OnColorChanged"
|
|
||||||
Color="{Binding Config.LedColor, Mode=TwoWay}">
|
|
||||||
</ui:ColorPickerButton>
|
|
||||||
</Grid>
|
</Grid>
|
||||||
</Border>
|
</Border>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|||||||
@@ -6,12 +6,10 @@ using Avalonia.Interactivity;
|
|||||||
using Avalonia.LogicalTree;
|
using Avalonia.LogicalTree;
|
||||||
using FluentAvalonia.UI.Controls;
|
using FluentAvalonia.UI.Controls;
|
||||||
using Ryujinx.Ava.UI.Helpers;
|
using Ryujinx.Ava.UI.Helpers;
|
||||||
using Ryujinx.Ava.UI.Models;
|
|
||||||
using Ryujinx.Ava.UI.ViewModels.Input;
|
using Ryujinx.Ava.UI.ViewModels.Input;
|
||||||
using Ryujinx.Common.Configuration.Hid.Controller;
|
using Ryujinx.Common.Configuration.Hid.Controller;
|
||||||
using Ryujinx.Input;
|
using Ryujinx.Input;
|
||||||
using Ryujinx.Input.Assigner;
|
using Ryujinx.Input.Assigner;
|
||||||
using System.Linq;
|
|
||||||
using Button = Ryujinx.Input.Button;
|
using Button = Ryujinx.Input.Button;
|
||||||
using StickInputId = Ryujinx.Common.Configuration.Hid.Controller.StickInputId;
|
using StickInputId = Ryujinx.Common.Configuration.Hid.Controller.StickInputId;
|
||||||
|
|
||||||
@@ -246,24 +244,5 @@ namespace Ryujinx.Ava.UI.Views.Input
|
|||||||
_currentAssigner?.Cancel();
|
_currentAssigner?.Cancel();
|
||||||
_currentAssigner = null;
|
_currentAssigner = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ColorPickerButton_OnColorChanged(ColorPickerButton sender, ColorButtonColorChangedEventArgs args)
|
|
||||||
{
|
|
||||||
if (!args.NewColor.HasValue) return;
|
|
||||||
if (DataContext is not ControllerInputViewModel cVm) return;
|
|
||||||
if (!cVm.Config.EnableLedChanging) return;
|
|
||||||
if (cVm.Config.TurnOffLed) return;
|
|
||||||
|
|
||||||
cVm.ParentModel.SelectedGamepad.SetLed(args.NewColor.Value.ToUInt32());
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ColorPickerButton_OnAttachedToVisualTree(object sender, VisualTreeAttachmentEventArgs e)
|
|
||||||
{
|
|
||||||
if (DataContext is not ControllerInputViewModel cVm) return;
|
|
||||||
if (!cVm.Config.EnableLedChanging) return;
|
|
||||||
if (cVm.Config.TurnOffLed) return;
|
|
||||||
|
|
||||||
cVm.ParentModel.SelectedGamepad.SetLed(cVm.Config.LedColor.ToUInt32());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -312,12 +312,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"
|
||||||
|
|||||||
46
src/Ryujinx/UI/Views/Input/LedInputView.axaml
Normal file
46
src/Ryujinx/UI/Views/Input/LedInputView.axaml
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
<UserControl xmlns="https://github.com/avaloniaui"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:controls="clr-namespace:Ryujinx.Ava.UI.Controls"
|
||||||
|
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
||||||
|
xmlns:ext="clr-namespace:Ryujinx.Ava.Common.Markup"
|
||||||
|
xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels.Input"
|
||||||
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||||
|
x:DataType="viewModels:LedInputViewModel"
|
||||||
|
x:Class="Ryujinx.UI.Views.Input.LedInputView">
|
||||||
|
<StackPanel Orientation="Vertical" HorizontalAlignment="Center">
|
||||||
|
<StackPanel Orientation="Horizontal" IsVisible="{Binding ParentModel.CanClearLed}">
|
||||||
|
<TextBlock MinWidth="75" MaxWidth="150" Text="{ext:Locale ControllerSettingsLedColorDisable}" />
|
||||||
|
<CheckBox
|
||||||
|
Margin="5"
|
||||||
|
MinWidth="0"
|
||||||
|
IsChecked="{Binding TurnOffLed, Mode=TwoWay}"
|
||||||
|
Command="{Binding LedDisabledChanged}">
|
||||||
|
</CheckBox>
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Orientation="Horizontal" IsEnabled="{Binding !TurnOffLed}">
|
||||||
|
<TextBlock MinWidth="75" MaxWidth="150" Text="{ext:Locale ControllerSettingsLedColorRainbow}" />
|
||||||
|
<CheckBox
|
||||||
|
Margin="5"
|
||||||
|
MinWidth="0"
|
||||||
|
IsChecked="{Binding UseRainbowLed, Mode=TwoWay}">
|
||||||
|
</CheckBox>
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Orientation="Horizontal" IsEnabled="{Binding ShowLedColorPicker}">
|
||||||
|
<TextBlock MinWidth="75" MaxWidth="150" Text="{ext:Locale ControllerSettingsLedColor}" />
|
||||||
|
<ui:ColorPickerButton
|
||||||
|
Margin="5"
|
||||||
|
IsMoreButtonVisible="False"
|
||||||
|
UseColorPalette="False"
|
||||||
|
UseColorTriangle="False"
|
||||||
|
UseColorWheel="False"
|
||||||
|
ShowAcceptDismissButtons="False"
|
||||||
|
IsAlphaEnabled="False"
|
||||||
|
AttachedToVisualTree="ColorPickerButton_OnAttachedToVisualTree"
|
||||||
|
ColorChanged="ColorPickerButton_OnColorChanged"
|
||||||
|
Color="{Binding LedColor, Mode=TwoWay}">
|
||||||
|
</ui:ColorPickerButton>
|
||||||
|
</StackPanel>
|
||||||
|
</StackPanel>
|
||||||
|
</UserControl>
|
||||||
75
src/Ryujinx/UI/Views/Input/LedInputView.axaml.cs
Normal file
75
src/Ryujinx/UI/Views/Input/LedInputView.axaml.cs
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
using Avalonia;
|
||||||
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Markup.Xaml;
|
||||||
|
using FluentAvalonia.UI.Controls;
|
||||||
|
using Ryujinx.Ava.Common.Locale;
|
||||||
|
using Ryujinx.Ava.UI.Models.Input;
|
||||||
|
using Ryujinx.Ava.UI.ViewModels.Input;
|
||||||
|
using Ryujinx.Ava.UI.Views.Input;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Ryujinx.UI.Views.Input
|
||||||
|
{
|
||||||
|
public partial class LedInputView : UserControl
|
||||||
|
{
|
||||||
|
private readonly LedInputViewModel _viewModel;
|
||||||
|
|
||||||
|
public LedInputView(ControllerInputViewModel viewModel)
|
||||||
|
{
|
||||||
|
DataContext = _viewModel = new LedInputViewModel
|
||||||
|
{
|
||||||
|
ParentModel = viewModel.ParentModel,
|
||||||
|
TurnOffLed = viewModel.Config.TurnOffLed,
|
||||||
|
EnableLedChanging = viewModel.Config.EnableLedChanging,
|
||||||
|
LedColor = viewModel.Config.LedColor,
|
||||||
|
UseRainbowLed = viewModel.Config.UseRainbowLed,
|
||||||
|
};
|
||||||
|
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ColorPickerButton_OnColorChanged(ColorPickerButton sender, ColorButtonColorChangedEventArgs args)
|
||||||
|
{
|
||||||
|
if (!args.NewColor.HasValue) return;
|
||||||
|
if (DataContext is not LedInputViewModel lvm) return;
|
||||||
|
if (!lvm.EnableLedChanging) return;
|
||||||
|
if (lvm.TurnOffLed) return;
|
||||||
|
|
||||||
|
lvm.ParentModel.SelectedGamepad.SetLed(args.NewColor.Value.ToUInt32());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ColorPickerButton_OnAttachedToVisualTree(object sender, VisualTreeAttachmentEventArgs e)
|
||||||
|
{
|
||||||
|
if (DataContext is not LedInputViewModel lvm) return;
|
||||||
|
if (!lvm.EnableLedChanging) return;
|
||||||
|
if (lvm.TurnOffLed) return;
|
||||||
|
|
||||||
|
lvm.ParentModel.SelectedGamepad.SetLed(lvm.LedColor.ToUInt32());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async Task Show(ControllerInputViewModel viewModel)
|
||||||
|
{
|
||||||
|
LedInputView content = new(viewModel);
|
||||||
|
|
||||||
|
ContentDialog contentDialog = new()
|
||||||
|
{
|
||||||
|
Title = LocaleManager.Instance[LocaleKeys.ControllerLedTitle],
|
||||||
|
PrimaryButtonText = LocaleManager.Instance[LocaleKeys.ControllerSettingsSave],
|
||||||
|
SecondaryButtonText = string.Empty,
|
||||||
|
CloseButtonText = LocaleManager.Instance[LocaleKeys.ControllerSettingsClose],
|
||||||
|
Content = content,
|
||||||
|
};
|
||||||
|
contentDialog.PrimaryButtonClick += (sender, args) =>
|
||||||
|
{
|
||||||
|
GamepadInputConfig config = viewModel.Config;
|
||||||
|
config.EnableLedChanging = content._viewModel.EnableLedChanging;
|
||||||
|
config.LedColor = content._viewModel.LedColor;
|
||||||
|
config.UseRainbowLed = content._viewModel.UseRainbowLed;
|
||||||
|
config.TurnOffLed = content._viewModel.TurnOffLed;
|
||||||
|
};
|
||||||
|
|
||||||
|
await contentDialog.ShowAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -11,7 +11,7 @@
|
|||||||
xmlns:settings="clr-namespace:Ryujinx.Ava.UI.Views.Settings"
|
xmlns:settings="clr-namespace:Ryujinx.Ava.UI.Views.Settings"
|
||||||
xmlns:helpers="clr-namespace:Ryujinx.Ava.UI.Helpers"
|
xmlns:helpers="clr-namespace:Ryujinx.Ava.UI.Helpers"
|
||||||
Width="1100"
|
Width="1100"
|
||||||
Height="768"
|
Height="850"
|
||||||
MinWidth="800"
|
MinWidth="800"
|
||||||
MinHeight="480"
|
MinHeight="480"
|
||||||
WindowStartupLocation="CenterOwner"
|
WindowStartupLocation="CenterOwner"
|
||||||
|
|||||||
Reference in New Issue
Block a user