Ava UI: Input Menu Refactor (#5826)

* Refactor

* Apply suggestions from code review

Co-authored-by: Ac_K <Acoustik666@gmail.com>

* Update src/Ryujinx/UI/Views/Settings/SettingsHotkeysView.axaml.cs

Co-authored-by: Ac_K <Acoustik666@gmail.com>

* Update src/Ryujinx.Input/ButtonValueType.cs

Co-authored-by: Ac_K <Acoustik666@gmail.com>

* Add empty line

* Requested renames

* Update src/Ryujinx/UI/Views/Settings/SettingsHotkeysView.axaml.cs

Co-authored-by: gdkchan <gab.dark.100@gmail.com>

* Make parent models private readonly

* Fix ControllerInputView

* Make line shorter

* Mac keys in locale

* Double line break

* Fix build

* Get rid of _isValid

* Fix potential race condition

* Rename HasAnyButtonPressed to IsAnyButtonPressed

* Use switches

* Simplify enumeration

---------

Co-authored-by: Ac_K <Acoustik666@gmail.com>
Co-authored-by: gdkchan <gab.dark.100@gmail.com>
Co-authored-by: TSR Berry <20988865+TSRBerry@users.noreply.github.com>
This commit is contained in:
Isaac Marovitz 2024-04-17 22:52:12 +01:00 committed by GitHub
parent 8884d1fd73
commit 446f2854a5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
38 changed files with 3402 additions and 1275 deletions

View file

@ -0,0 +1,84 @@
using Avalonia.Svg.Skia;
using Ryujinx.Ava.UI.Models.Input;
using Ryujinx.Ava.UI.Views.Input;
namespace Ryujinx.Ava.UI.ViewModels.Input
{
public class ControllerInputViewModel : BaseModel
{
private GamepadInputConfig _config;
public GamepadInputConfig Config
{
get => _config;
set
{
_config = value;
OnPropertyChanged();
}
}
private bool _isLeft;
public bool IsLeft
{
get => _isLeft;
set
{
_isLeft = value;
OnPropertyChanged();
OnPropertyChanged(nameof(HasSides));
}
}
private bool _isRight;
public bool IsRight
{
get => _isRight;
set
{
_isRight = value;
OnPropertyChanged();
OnPropertyChanged(nameof(HasSides));
}
}
public bool HasSides => IsLeft ^ IsRight;
private SvgImage _image;
public SvgImage Image
{
get => _image;
set
{
_image = value;
OnPropertyChanged();
}
}
public readonly InputViewModel ParentModel;
public ControllerInputViewModel(InputViewModel model, GamepadInputConfig config)
{
ParentModel = model;
model.NotifyChangesEvent += OnParentModelChanged;
OnParentModelChanged();
Config = config;
}
public async void ShowMotionConfig()
{
await MotionInputView.Show(this);
}
public async void ShowRumbleConfig()
{
await RumbleInputView.Show(this);
}
public void OnParentModelChanged()
{
IsLeft = ParentModel.IsLeft;
IsRight = ParentModel.IsRight;
Image = ParentModel.Image;
}
}
}

View file

@ -8,7 +8,7 @@ using Ryujinx.Ava.Common.Locale;
using Ryujinx.Ava.Input;
using Ryujinx.Ava.UI.Helpers;
using Ryujinx.Ava.UI.Models;
using Ryujinx.Ava.UI.Views.Input;
using Ryujinx.Ava.UI.Models.Input;
using Ryujinx.Ava.UI.Windows;
using Ryujinx.Common;
using Ryujinx.Common.Configuration;
@ -30,9 +30,9 @@ using ConfigGamepadInputId = Ryujinx.Common.Configuration.Hid.Controller.Gamepad
using ConfigStickInputId = Ryujinx.Common.Configuration.Hid.Controller.StickInputId;
using Key = Ryujinx.Common.Configuration.Hid.Key;
namespace Ryujinx.Ava.UI.ViewModels
namespace Ryujinx.Ava.UI.ViewModels.Input
{
public class ControllerInputViewModel : BaseModel, IDisposable
public class InputViewModel : BaseModel, IDisposable
{
private const string Disabled = "disabled";
private const string ProControllerResource = "Ryujinx.UI.Common/Resources/Controller_ProCon.svg";
@ -48,7 +48,7 @@ namespace Ryujinx.Ava.UI.ViewModels
private int _controllerNumber;
private string _controllerImage;
private int _device;
private object _configuration;
private object _configViewModel;
private string _profileName;
private bool _isLoaded;
@ -71,13 +71,14 @@ namespace Ryujinx.Ava.UI.ViewModels
public bool IsLeft { get; set; }
public bool IsModified { get; set; }
public event Action NotifyChangesEvent;
public object Configuration
public object ConfigViewModel
{
get => _configuration;
get => _configViewModel;
set
{
_configuration = value;
_configViewModel = value;
OnPropertyChanged();
}
@ -232,7 +233,7 @@ namespace Ryujinx.Ava.UI.ViewModels
public InputConfig Config { get; set; }
public ControllerInputViewModel(UserControl owner) : this()
public InputViewModel(UserControl owner) : this()
{
if (Program.PreviewerDetached)
{
@ -255,7 +256,7 @@ namespace Ryujinx.Ava.UI.ViewModels
}
}
public ControllerInputViewModel()
public InputViewModel()
{
PlayerIndexes = new ObservableCollection<PlayerModel>();
Controllers = new ObservableCollection<ControllerModel>();
@ -282,12 +283,12 @@ namespace Ryujinx.Ava.UI.ViewModels
if (Config is StandardKeyboardInputConfig keyboardInputConfig)
{
Configuration = new InputConfiguration<Key, ConfigStickInputId>(keyboardInputConfig);
ConfigViewModel = new KeyboardInputViewModel(this, new KeyboardInputConfig(keyboardInputConfig));
}
if (Config is StandardControllerInputConfig controllerInputConfig)
{
Configuration = new InputConfiguration<ConfigGamepadInputId, ConfigStickInputId>(controllerInputConfig);
ConfigViewModel = new ControllerInputViewModel(this, new GamepadInputConfig(controllerInputConfig));
}
}
@ -323,16 +324,6 @@ namespace Ryujinx.Ava.UI.ViewModels
}
}
public async void ShowMotionConfig()
{
await MotionInputView.Show(this);
}
public async void ShowRumbleConfig()
{
await RumbleInputView.Show(this);
}
private void LoadInputDriver()
{
if (_device < 0)
@ -740,7 +731,7 @@ namespace Ryujinx.Ava.UI.ViewModels
return;
}
if (Configuration == null)
if (ConfigViewModel == null)
{
return;
}
@ -751,35 +742,37 @@ namespace Ryujinx.Ava.UI.ViewModels
return;
}
bool validFileName = ProfileName.IndexOfAny(Path.GetInvalidFileNameChars()) == -1;
if (validFileName)
{
string path = Path.Combine(GetProfileBasePath(), ProfileName + ".json");
InputConfig config = null;
if (IsKeyboard)
{
config = (Configuration as InputConfiguration<Key, ConfigStickInputId>).GetConfig();
}
else if (IsController)
{
config = (Configuration as InputConfiguration<GamepadInputId, ConfigStickInputId>).GetConfig();
}
config.ControllerType = Controllers[_controller].Type;
string jsonString = JsonHelper.Serialize(config, _serializerContext.InputConfig);
await File.WriteAllTextAsync(path, jsonString);
LoadProfiles();
}
else
{
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogProfileInvalidProfileNameErrorMessage]);
bool validFileName = ProfileName.IndexOfAny(Path.GetInvalidFileNameChars()) == -1;
if (validFileName)
{
string path = Path.Combine(GetProfileBasePath(), ProfileName + ".json");
InputConfig config = null;
if (IsKeyboard)
{
config = (ConfigViewModel as KeyboardInputViewModel).Config.GetConfig();
}
else if (IsController)
{
config = (ConfigViewModel as ControllerInputViewModel).Config.GetConfig();
}
config.ControllerType = Controllers[_controller].Type;
string jsonString = JsonHelper.Serialize(config, _serializerContext.InputConfig);
await File.WriteAllTextAsync(path, jsonString);
LoadProfiles();
}
else
{
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogProfileInvalidProfileNameErrorMessage]);
}
}
}
@ -830,18 +823,18 @@ namespace Ryujinx.Ava.UI.ViewModels
if (device.Type == DeviceType.Keyboard)
{
var inputConfig = Configuration as InputConfiguration<Key, ConfigStickInputId>;
var inputConfig = (ConfigViewModel as KeyboardInputViewModel).Config;
inputConfig.Id = device.Id;
}
else
{
var inputConfig = Configuration as InputConfiguration<GamepadInputId, ConfigStickInputId>;
var inputConfig = (ConfigViewModel as ControllerInputViewModel).Config;
inputConfig.Id = device.Id.Split(" ")[0];
}
var config = !IsController
? (Configuration as InputConfiguration<Key, ConfigStickInputId>).GetConfig()
: (Configuration as InputConfiguration<GamepadInputId, ConfigStickInputId>).GetConfig();
? (ConfigViewModel as KeyboardInputViewModel).Config.GetConfig()
: (ConfigViewModel as ControllerInputViewModel).Config.GetConfig();
config.ControllerType = Controllers[_controller].Type;
config.PlayerIndex = _playerId;
@ -872,12 +865,13 @@ namespace Ryujinx.Ava.UI.ViewModels
public void NotifyChanges()
{
OnPropertyChanged(nameof(Configuration));
OnPropertyChanged(nameof(ConfigViewModel));
OnPropertyChanged(nameof(IsController));
OnPropertyChanged(nameof(ShowSettings));
OnPropertyChanged(nameof(IsKeyboard));
OnPropertyChanged(nameof(IsRight));
OnPropertyChanged(nameof(IsLeft));
NotifyChangesEvent?.Invoke();
}
public void Dispose()

View file

@ -0,0 +1,73 @@
using Avalonia.Svg.Skia;
using Ryujinx.Ava.UI.Models.Input;
namespace Ryujinx.Ava.UI.ViewModels.Input
{
public class KeyboardInputViewModel : BaseModel
{
private KeyboardInputConfig _config;
public KeyboardInputConfig Config
{
get => _config;
set
{
_config = value;
OnPropertyChanged();
}
}
private bool _isLeft;
public bool IsLeft
{
get => _isLeft;
set
{
_isLeft = value;
OnPropertyChanged();
OnPropertyChanged(nameof(HasSides));
}
}
private bool _isRight;
public bool IsRight
{
get => _isRight;
set
{
_isRight = value;
OnPropertyChanged();
OnPropertyChanged(nameof(HasSides));
}
}
public bool HasSides => IsLeft ^ IsRight;
private SvgImage _image;
public SvgImage Image
{
get => _image;
set
{
_image = value;
OnPropertyChanged();
}
}
public readonly InputViewModel ParentModel;
public KeyboardInputViewModel(InputViewModel model, KeyboardInputConfig config)
{
ParentModel = model;
model.NotifyChangesEvent += OnParentModelChanged;
OnParentModelChanged();
Config = config;
}
public void OnParentModelChanged()
{
IsLeft = ParentModel.IsLeft;
IsRight = ParentModel.IsRight;
Image = ParentModel.Image;
}
}
}

View file

@ -1,4 +1,4 @@
namespace Ryujinx.Ava.UI.ViewModels
namespace Ryujinx.Ava.UI.ViewModels.Input
{
public class MotionInputViewModel : BaseModel
{

View file

@ -1,4 +1,4 @@
namespace Ryujinx.Ava.UI.ViewModels
namespace Ryujinx.Ava.UI.ViewModels.Input
{
public class RumbleInputViewModel : BaseModel
{

View file

@ -7,9 +7,9 @@ using Ryujinx.Audio.Backends.SDL2;
using Ryujinx.Audio.Backends.SoundIo;
using Ryujinx.Ava.Common.Locale;
using Ryujinx.Ava.UI.Helpers;
using Ryujinx.Ava.UI.Models.Input;
using Ryujinx.Ava.UI.Windows;
using Ryujinx.Common.Configuration;
using Ryujinx.Common.Configuration.Hid;
using Ryujinx.Common.Configuration.Multiplayer;
using Ryujinx.Common.GraphicsDriver;
using Ryujinx.Common.Logging;
@ -46,7 +46,6 @@ namespace Ryujinx.Ava.UI.ViewModels
private bool _isVulkanAvailable = true;
private bool _directoryChanged;
private readonly List<string> _gpuIds = new();
private KeyboardHotkeys _keyboardHotkeys;
private int _graphicsBackendIndex;
private int _scalingFilter;
private int _scalingFilterLevel;
@ -237,16 +236,7 @@ namespace Ryujinx.Ava.UI.ViewModels
get => new(_networkInterfaces.Keys);
}
public KeyboardHotkeys KeyboardHotkeys
{
get => _keyboardHotkeys;
set
{
_keyboardHotkeys = value;
OnPropertyChanged();
}
}
public HotkeyConfig KeyboardHotkey { get; set; }
public int NetworkInterfaceIndex
{
@ -413,7 +403,7 @@ namespace Ryujinx.Ava.UI.ViewModels
EnableMouse = config.Hid.EnableMouse;
// Keyboard Hotkeys
KeyboardHotkeys = config.Hid.Hotkeys.Value;
KeyboardHotkey = new HotkeyConfig(config.Hid.Hotkeys.Value);
// System
Region = (int)config.System.Region.Value;
@ -500,7 +490,7 @@ namespace Ryujinx.Ava.UI.ViewModels
config.Hid.EnableMouse.Value = EnableMouse;
// Keyboard Hotkeys
config.Hid.Hotkeys.Value = KeyboardHotkeys;
config.Hid.Hotkeys.Value = KeyboardHotkey.GetConfig();
// System
config.System.Region.Value = (Region)Region;