From 49b37550cae6b3c69f59a9c7a44b17e3c12a813b Mon Sep 17 00:00:00 2001 From: Isaac Marovitz <42140194+IsaacMarovitz@users.noreply.github.com> Date: Sat, 21 Oct 2023 07:26:51 -0400 Subject: Ava UI: Input Menu Refactor (#4998) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * So much boilerplate * Slow and steady * Restructure + Ack suggestions * Restructure + Ack suggestions * Restructure * Clean * Propogate those fields i forgot about * It builds * Progress * Almost there * Fix stupid mistake * Fix more stupid mistakes * Actually fix fuck ups * Start localising * r/therestofthefuckingowl * Localise ButtonKeyAssigner * Are you feeling it now mr krabs * We’re done at last * Crimes against code * Try me in the Hague * Please be quiet * Crimes are here to stay * Dispose stuff * Cleanup a couple things * Visual fixes and improvements One weird bug * Fix rebase errors * Fixes * Ack Suggestions Remaining ack suggestions Update src/Ryujinx.Ava/UI/Models/Input/ControllerInputConfig.cs Co-authored-by: Ac_K Update src/Ryujinx.Ava/UI/Models/Input/ControllerInputConfig.cs Co-authored-by: Ac_K * Formatting and error More Ava 11-ness Whoops * Code style fixes * Style fixes * Analyzer fix * Remove all ReflectionBindings * Remove ambigious object * Remove redundant property * Old man yells at formatter * r e a d o n l y * Fix profiles * Use new Sliders --------- Co-authored-by: Ac_K --- .../UI/Views/Input/ControllerInputView.axaml | 616 ++++--------------- .../UI/Views/Input/ControllerInputView.axaml.cs | 160 ++--- src/Ryujinx.Ava/UI/Views/Input/InputView.axaml | 225 +++++++ src/Ryujinx.Ava/UI/Views/Input/InputView.axaml.cs | 61 ++ .../UI/Views/Input/KeyboardInputView.axaml | 675 +++++++++++++++++++++ .../UI/Views/Input/KeyboardInputView.axaml.cs | 210 +++++++ .../UI/Views/Input/MotionInputView.axaml | 2 +- .../UI/Views/Input/MotionInputView.axaml.cs | 8 +- .../UI/Views/Input/RumbleInputView.axaml | 2 +- .../UI/Views/Input/RumbleInputView.axaml.cs | 8 +- 10 files changed, 1391 insertions(+), 576 deletions(-) create mode 100644 src/Ryujinx.Ava/UI/Views/Input/InputView.axaml create mode 100644 src/Ryujinx.Ava/UI/Views/Input/InputView.axaml.cs create mode 100644 src/Ryujinx.Ava/UI/Views/Input/KeyboardInputView.axaml create mode 100644 src/Ryujinx.Ava/UI/Views/Input/KeyboardInputView.axaml.cs (limited to 'src/Ryujinx.Ava/UI/Views/Input') diff --git a/src/Ryujinx.Ava/UI/Views/Input/ControllerInputView.axaml b/src/Ryujinx.Ava/UI/Views/Input/ControllerInputView.axaml index d636873a..08bdf90f 100644 --- a/src/Ryujinx.Ava/UI/Views/Input/ControllerInputView.axaml +++ b/src/Ryujinx.Ava/UI/Views/Input/ControllerInputView.axaml @@ -1,13 +1,11 @@ @@ -34,191 +33,10 @@ HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Orientation="Vertical"> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + MinHeight="450"> @@ -257,9 +75,9 @@ VerticalAlignment="Center" Text="{locale:Locale ControllerSettingsTriggerZL}" TextAlignment="Center" /> - + @@ -273,9 +91,9 @@ VerticalAlignment="Center" Text="{locale:Locale ControllerSettingsTriggerL}" TextAlignment="Center" /> - + @@ -289,9 +107,9 @@ VerticalAlignment="Center" Text="{locale:Locale ControllerSettingsButtonMinus}" TextAlignment="Center" /> - + @@ -311,100 +129,8 @@ Margin="0,0,0,10" HorizontalAlignment="Center" Text="{locale:Locale ControllerSettingsLStick}" /> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + @@ -415,9 +141,9 @@ VerticalAlignment="Center" Text="{locale:Locale ControllerSettingsStickButton}" TextAlignment="Center" /> - + @@ -432,22 +158,22 @@ VerticalAlignment="Center" Text="{locale:Locale ControllerSettingsStickStick}" TextAlignment="Center" /> - + - + - + - + + Value="{Binding Config.DeadzoneLeft, Mode=TwoWay}" /> + Text="{Binding Config.DeadzoneLeft, StringFormat=\{0:0.00\}}" /> + Value="{Binding Config.RangeLeft, Mode=TwoWay}" /> + Text="{Binding Config.RangeLeft, StringFormat=\{0:0.00\}}" /> @@ -525,9 +251,9 @@ VerticalAlignment="Center" Text="{locale:Locale ControllerSettingsDPadUp}" TextAlignment="Center" /> - + @@ -542,9 +268,9 @@ VerticalAlignment="Center" Text="{locale:Locale ControllerSettingsDPadDown}" TextAlignment="Center" /> - + @@ -559,9 +285,9 @@ VerticalAlignment="Center" Text="{locale:Locale ControllerSettingsDPadLeft}" TextAlignment="Center" /> - + @@ -576,9 +302,9 @@ VerticalAlignment="Center" Text="{locale:Locale ControllerSettingsDPadRight}" TextAlignment="Center" /> - + @@ -591,6 +317,13 @@ Grid.Column="1" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"> + + + Value="{Binding Config.TriggerThreshold, Mode=TwoWay}" /> + Text="{Binding Config.TriggerThreshold, StringFormat=\{0:0.00\}}" /> - + - + IsVisible="{Binding IsLeft}" + Orientation="Horizontal"> - - - - + + + + - + IsVisible="{Binding IsLeft}" + Orientation="Horizontal"> - - - - + + + + - + IsVisible="{Binding IsRight}" + Orientation="Horizontal"> - - - - + + + + - + IsVisible="{Binding IsRight}" + Orientation="Horizontal"> - + + + + - - + HorizontalAlignment="Stretch"> @@ -720,7 +449,7 @@ Margin="10" MinWidth="0" Grid.Column="0" - IsChecked="{ReflectionBinding Configuration.EnableMotion, Mode=TwoWay}"> + IsChecked="{Binding Config.EnableMotion, Mode=TwoWay}"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Ryujinx.Ava/UI/Views/Input/InputView.axaml.cs b/src/Ryujinx.Ava/UI/Views/Input/InputView.axaml.cs new file mode 100644 index 00000000..356381a8 --- /dev/null +++ b/src/Ryujinx.Ava/UI/Views/Input/InputView.axaml.cs @@ -0,0 +1,61 @@ +using Avalonia.Controls; +using Ryujinx.Ava.Common.Locale; +using Ryujinx.Ava.UI.Helpers; +using Ryujinx.Ava.UI.Models; +using Ryujinx.Ava.UI.ViewModels.Input; + +namespace Ryujinx.Ava.UI.Views.Input +{ + public partial class InputView : UserControl + { + private bool _dialogOpen; + private InputViewModel ViewModel { get; set; } + + public InputView() + { + DataContext = ViewModel = new InputViewModel(this); + + InitializeComponent(); + } + + public void SaveCurrentProfile() + { + ViewModel.Save(); + } + + private async void PlayerIndexBox_OnSelectionChanged(object sender, SelectionChangedEventArgs e) + { + if (ViewModel.IsModified && !_dialogOpen) + { + _dialogOpen = true; + + var result = await ContentDialogHelper.CreateConfirmationDialog( + LocaleManager.Instance[LocaleKeys.DialogControllerSettingsModifiedConfirmMessage], + LocaleManager.Instance[LocaleKeys.DialogControllerSettingsModifiedConfirmSubMessage], + LocaleManager.Instance[LocaleKeys.InputDialogYes], + LocaleManager.Instance[LocaleKeys.InputDialogNo], + LocaleManager.Instance[LocaleKeys.RyujinxConfirm]); + + if (result == UserResult.Yes) + { + ViewModel.Save(); + } + + _dialogOpen = false; + + ViewModel.IsModified = false; + + if (e.AddedItems.Count > 0) + { + var player = (PlayerModel)e.AddedItems[0]; + ViewModel.PlayerId = player.Id; + } + } + } + + public void Dispose() + { + ViewModel.Dispose(); + } + } +} diff --git a/src/Ryujinx.Ava/UI/Views/Input/KeyboardInputView.axaml b/src/Ryujinx.Ava/UI/Views/Input/KeyboardInputView.axaml new file mode 100644 index 00000000..e4566f46 --- /dev/null +++ b/src/Ryujinx.Ava/UI/Views/Input/KeyboardInputView.axaml @@ -0,0 +1,675 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Ryujinx.Ava/UI/Views/Input/KeyboardInputView.axaml.cs b/src/Ryujinx.Ava/UI/Views/Input/KeyboardInputView.axaml.cs new file mode 100644 index 00000000..f7024c5d --- /dev/null +++ b/src/Ryujinx.Ava/UI/Views/Input/KeyboardInputView.axaml.cs @@ -0,0 +1,210 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Controls.Primitives; +using Avalonia.Input; +using Avalonia.Interactivity; +using Avalonia.LogicalTree; +using Ryujinx.Ava.UI.Helpers; +using Ryujinx.Ava.UI.ViewModels.Input; +using Ryujinx.Input; +using Ryujinx.Input.Assigner; + +namespace Ryujinx.Ava.UI.Views.Input +{ + public partial class KeyboardInputView : UserControl + { + private ButtonKeyAssigner _currentAssigner; + + public KeyboardInputView() + { + InitializeComponent(); + + foreach (ILogical visual in SettingButtons.GetLogicalDescendants()) + { + if (visual is ToggleButton button and not CheckBox) + { + button.IsCheckedChanged += Button_IsCheckedChanged; + } + } + } + + protected override void OnPointerReleased(PointerReleasedEventArgs e) + { + base.OnPointerReleased(e); + + if (_currentAssigner != null && _currentAssigner.ToggledButton != null && !_currentAssigner.ToggledButton.IsPointerOver) + { + _currentAssigner.Cancel(); + } + } + + private void Button_IsCheckedChanged(object sender, RoutedEventArgs e) + { + if (sender is ToggleButton button) + { + if ((bool)button.IsChecked) + { + if (_currentAssigner != null && button == _currentAssigner.ToggledButton) + { + return; + } + + bool isStick = button.Tag != null && button.Tag.ToString() == "stick"; + + if (_currentAssigner == null && (bool)button.IsChecked) + { + _currentAssigner = new ButtonKeyAssigner(button); + + this.Focus(NavigationMethod.Pointer); + + PointerPressed += MouseClick; + + IKeyboard keyboard = (IKeyboard)(DataContext as KeyboardInputViewModel).parentModel.AvaloniaKeyboardDriver.GetGamepad("0"); // Open Avalonia keyboard for cancel operations. + IButtonAssigner assigner = CreateButtonAssigner(isStick); + + _currentAssigner.ButtonAssigned += (sender, e) => + { + if (e.ButtonValue.HasValue) + { + var viewModel = (DataContext as KeyboardInputViewModel); + var buttonValue = e.ButtonValue.Value; + viewModel.parentModel.IsModified = true; + + switch (button.Name) + { + case "ButtonZl": + viewModel.Config.ButtonZl = buttonValue.AsKey(); + break; + case "ButtonL": + viewModel.Config.ButtonL = buttonValue.AsKey(); + break; + case "ButtonMinus": + viewModel.Config.ButtonMinus = buttonValue.AsKey(); + break; + case "LeftStickButton": + viewModel.Config.LeftStickButton = buttonValue.AsKey(); + break; + case "LeftStickUp": + viewModel.Config.LeftStickUp = buttonValue.AsKey(); + break; + case "LeftStickDown": + viewModel.Config.LeftStickDown = buttonValue.AsKey(); + break; + case "LeftStickRight": + viewModel.Config.LeftStickRight = buttonValue.AsKey(); + break; + case "LeftStickLeft": + viewModel.Config.LeftStickLeft = buttonValue.AsKey(); + break; + case "DpadUp": + viewModel.Config.DpadUp = buttonValue.AsKey(); + break; + case "DpadDown": + viewModel.Config.DpadDown = buttonValue.AsKey(); + break; + case "DpadLeft": + viewModel.Config.DpadLeft = buttonValue.AsKey(); + break; + case "DpadRight": + viewModel.Config.DpadRight = buttonValue.AsKey(); + break; + case "LeftButtonSr": + viewModel.Config.LeftButtonSr = buttonValue.AsKey(); + break; + case "LeftButtonSl": + viewModel.Config.LeftButtonSl = buttonValue.AsKey(); + break; + case "RightButtonSr": + viewModel.Config.RightButtonSr = buttonValue.AsKey(); + break; + case "RightButtonSl": + viewModel.Config.RightButtonSl = buttonValue.AsKey(); + break; + case "ButtonZr": + viewModel.Config.ButtonZr = buttonValue.AsKey(); + break; + case "ButtonR": + viewModel.Config.ButtonR = buttonValue.AsKey(); + break; + case "ButtonPlus": + viewModel.Config.ButtonPlus = buttonValue.AsKey(); + break; + case "ButtonA": + viewModel.Config.ButtonA = buttonValue.AsKey(); + break; + case "ButtonB": + viewModel.Config.ButtonB = buttonValue.AsKey(); + break; + case "ButtonX": + viewModel.Config.ButtonX = buttonValue.AsKey(); + break; + case "ButtonY": + viewModel.Config.ButtonY = buttonValue.AsKey(); + break; + case "RightStickButton": + viewModel.Config.RightStickButton = buttonValue.AsKey(); + break; + case "RightStickUp": + viewModel.Config.RightStickUp = buttonValue.AsKey(); + break; + case "RightStickDown": + viewModel.Config.RightStickDown = buttonValue.AsKey(); + break; + case "RightStickRight": + viewModel.Config.RightStickRight = buttonValue.AsKey(); + break; + case "RightStickLeft": + viewModel.Config.RightStickLeft = buttonValue.AsKey(); + break; + } + } + }; + + _currentAssigner.GetInputAndAssign(assigner, keyboard); + } + else + { + if (_currentAssigner != null) + { + ToggleButton oldButton = _currentAssigner.ToggledButton; + + _currentAssigner.Cancel(); + _currentAssigner = null; + button.IsChecked = false; + } + } + } + else + { + _currentAssigner?.Cancel(); + _currentAssigner = null; + } + } + } + + private void MouseClick(object sender, PointerPressedEventArgs e) + { + bool shouldUnbind = e.GetCurrentPoint(this).Properties.IsMiddleButtonPressed; + + _currentAssigner?.Cancel(shouldUnbind); + + PointerPressed -= MouseClick; + } + + private IButtonAssigner CreateButtonAssigner(bool forStick) + { + IButtonAssigner assigner; + + assigner = new KeyboardKeyAssigner((IKeyboard)(DataContext as KeyboardInputViewModel).parentModel.SelectedGamepad); + + return assigner; + } + + protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e) + { + base.OnDetachedFromVisualTree(e); + _currentAssigner?.Cancel(); + _currentAssigner = null; + } + } +} diff --git a/src/Ryujinx.Ava/UI/Views/Input/MotionInputView.axaml b/src/Ryujinx.Ava/UI/Views/Input/MotionInputView.axaml index a6b587f6..0d018e29 100644 --- a/src/Ryujinx.Ava/UI/Views/Input/MotionInputView.axaml +++ b/src/Ryujinx.Ava/UI/Views/Input/MotionInputView.axaml @@ -6,7 +6,7 @@ xmlns:controls="clr-namespace:Ryujinx.Ava.UI.Controls" xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia" xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale" - xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels" + xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels.Input" mc:Ignorable="d" x:Class="Ryujinx.Ava.UI.Views.Input.MotionInputView" x:DataType="viewModels:MotionInputViewModel" diff --git a/src/Ryujinx.Ava/UI/Views/Input/MotionInputView.axaml.cs b/src/Ryujinx.Ava/UI/Views/Input/MotionInputView.axaml.cs index 1b340752..2304364b 100644 --- a/src/Ryujinx.Ava/UI/Views/Input/MotionInputView.axaml.cs +++ b/src/Ryujinx.Ava/UI/Views/Input/MotionInputView.axaml.cs @@ -1,9 +1,7 @@ using Avalonia.Controls; using FluentAvalonia.UI.Controls; using Ryujinx.Ava.Common.Locale; -using Ryujinx.Ava.UI.Models; -using Ryujinx.Ava.UI.ViewModels; -using Ryujinx.Common.Configuration.Hid.Controller; +using Ryujinx.Ava.UI.ViewModels.Input; using System.Threading.Tasks; namespace Ryujinx.Ava.UI.Views.Input @@ -19,7 +17,7 @@ namespace Ryujinx.Ava.UI.Views.Input public MotionInputView(ControllerInputViewModel viewModel) { - var config = viewModel.Configuration as InputConfiguration; + var config = viewModel.Config; _viewModel = new MotionInputViewModel { @@ -51,7 +49,7 @@ namespace Ryujinx.Ava.UI.Views.Input }; contentDialog.PrimaryButtonClick += (sender, args) => { - var config = viewModel.Configuration as InputConfiguration; + var config = viewModel.Config; config.Slot = content._viewModel.Slot; config.Sensitivity = content._viewModel.Sensitivity; config.GyroDeadzone = content._viewModel.GyroDeadzone; diff --git a/src/Ryujinx.Ava/UI/Views/Input/RumbleInputView.axaml b/src/Ryujinx.Ava/UI/Views/Input/RumbleInputView.axaml index 5b7087a4..1beb1f06 100644 --- a/src/Ryujinx.Ava/UI/Views/Input/RumbleInputView.axaml +++ b/src/Ryujinx.Ava/UI/Views/Input/RumbleInputView.axaml @@ -5,7 +5,7 @@ xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale" - xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels" + xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels.Input" mc:Ignorable="d" x:Class="Ryujinx.Ava.UI.Views.Input.RumbleInputView" x:DataType="viewModels:RumbleInputViewModel" diff --git a/src/Ryujinx.Ava/UI/Views/Input/RumbleInputView.axaml.cs b/src/Ryujinx.Ava/UI/Views/Input/RumbleInputView.axaml.cs index 9307f872..58a4b416 100644 --- a/src/Ryujinx.Ava/UI/Views/Input/RumbleInputView.axaml.cs +++ b/src/Ryujinx.Ava/UI/Views/Input/RumbleInputView.axaml.cs @@ -1,9 +1,7 @@ using Avalonia.Controls; using FluentAvalonia.UI.Controls; using Ryujinx.Ava.Common.Locale; -using Ryujinx.Ava.UI.Models; -using Ryujinx.Ava.UI.ViewModels; -using Ryujinx.Common.Configuration.Hid.Controller; +using Ryujinx.Ava.UI.ViewModels.Input; using System.Threading.Tasks; namespace Ryujinx.Ava.UI.Views.Input @@ -19,7 +17,7 @@ namespace Ryujinx.Ava.UI.Views.Input public RumbleInputView(ControllerInputViewModel viewModel) { - var config = viewModel.Configuration as InputConfiguration; + var config = viewModel.Config; _viewModel = new RumbleInputViewModel { @@ -47,7 +45,7 @@ namespace Ryujinx.Ava.UI.Views.Input contentDialog.PrimaryButtonClick += (sender, args) => { - var config = viewModel.Configuration as InputConfiguration; + var config = viewModel.Config; config.StrongRumble = content._viewModel.StrongRumble; config.WeakRumble = content._viewModel.WeakRumble; }; -- cgit v1.2.3