diff --git a/src/Ryujinx/UI/ViewModels/Input/InputViewModel.cs b/src/Ryujinx/UI/ViewModels/Input/InputViewModel.cs index fbb545f8b..25e6e3fba 100644 --- a/src/Ryujinx/UI/ViewModels/Input/InputViewModel.cs +++ b/src/Ryujinx/UI/ViewModels/Input/InputViewModel.cs @@ -1188,6 +1188,16 @@ namespace Ryujinx.Ava.UI.ViewModels.Input } } + private void ApplySelectedProfileSilently(string profileName) + { + SetSelectedProfileSilently(profileName); + + if (TryLoadProfileConfiguration(profileName, out InputConfig profileConfig)) + { + LoadConfiguration(profileConfig, false); + } + } + private void RefreshProfileBindingState() { OnPropertyChanged(nameof(CanBindSelectedProfile)); @@ -1346,7 +1356,6 @@ namespace Ryujinx.Ava.UI.ViewModels.Input } LoadConfiguration(LoadDefaultConfiguration(), false); - SetSelectedProfileSilently(GetCurrentProfileDefaultName()); RefreshProfileBindingState(); } @@ -1428,12 +1437,22 @@ namespace Ryujinx.Ava.UI.ViewModels.Input { bool duplicateDeviceAssignmentChanged = _allowDuplicateDeviceAssignment.HasValue && _allowDuplicateDeviceAssignment.Value != GetSavedAllowDuplicateDeviceAssignment(); - bool configChanged = !ConfigsMatch(GetSelectedDeviceConfig(), GetDisplayedInputConfig(GetPersistedInputConfig())); + bool configChanged = !ConfigsMatch(GetSelectedDeviceConfig(), GetPersistedComparisonConfig()); bool playerAssignmentsChanged = !PlayerAssignmentsMatch(GetEditedPlayerInputAssignment(), GetPersistedPlayerInputAssignment()); return duplicateDeviceAssignmentChanged || configChanged || playerAssignmentsChanged; } + private InputConfig GetPersistedComparisonConfig() + { + if (!IsDefaultProfileName(ProfileName) && TryLoadProfileConfiguration(ProfileName, out InputConfig profileConfig)) + { + return profileConfig; + } + + return GetDisplayedInputConfig(GetPersistedInputConfig()); + } + private static bool ConfigsMatch(InputConfig currentConfig, InputConfig otherConfig) { if (currentConfig == null || otherConfig == null) @@ -1857,7 +1876,7 @@ namespace Ryujinx.Ava.UI.ViewModels.Input selectedProfile = GetCurrentProfileDefaultName(); } - SetSelectedProfileSilently(selectedProfile); + ApplySelectedProfileSilently(selectedProfile); } finally { @@ -2130,7 +2149,7 @@ namespace Ryujinx.Ava.UI.ViewModels.Input ReplaceBoundProfileName(ProfileName, null); LoadProfiles(); - SetSelectedProfileSilently(ProfilesList[0].ToString()); + ApplySelectedProfileSilently(ProfilesList[0].ToString()); RefreshModifiedState(); } } diff --git a/src/Ryujinx/UI/Views/Input/InputView.axaml b/src/Ryujinx/UI/Views/Input/InputView.axaml index 7b0a46bee..5f4b42094 100644 --- a/src/Ryujinx/UI/Views/Input/InputView.axaml +++ b/src/Ryujinx/UI/Views/Input/InputView.axaml @@ -106,6 +106,8 @@ IsEnabled="{Binding ShowSettings}" SelectedItem="{Binding ChosenProfile, Mode=TwoWay}" SelectionChanged="ComboBox_SelectionChanged" + GotFocus="ProfileBox_OnGotFocus" + LostFocus="ProfileBox_OnLostFocus" ItemsSource="{Binding ProfilesList}" Text="{Binding ProfileName, Mode=TwoWay}"> @@ -124,11 +126,12 @@ diff --git a/src/Ryujinx/UI/Views/Input/InputView.axaml.cs b/src/Ryujinx/UI/Views/Input/InputView.axaml.cs index 57bfa7e1c..d80ef2a10 100644 --- a/src/Ryujinx/UI/Views/Input/InputView.axaml.cs +++ b/src/Ryujinx/UI/Views/Input/InputView.axaml.cs @@ -2,6 +2,7 @@ using Avalonia.Controls; using Avalonia.Controls.Templates; using Avalonia.Interactivity; using Avalonia; +using Avalonia.Input; using Avalonia.Layout; using Avalonia.Media; using FluentAvalonia.UI.Controls; @@ -11,12 +12,15 @@ using Ryujinx.Ava.UI.Controls; using Ryujinx.Ava.UI.Helpers; using Ryujinx.Ava.UI.Models; using Ryujinx.Ava.UI.ViewModels.Input; +using System.ComponentModel; namespace Ryujinx.Ava.UI.Views.Input { public partial class InputView : RyujinxControl { private bool _dialogOpen; + private bool _isEditingProfileName; + private InputViewModel _subscribedViewModel; public InputView() { @@ -43,11 +47,24 @@ namespace Ryujinx.Ava.UI.Views.Input private void ReplaceViewModel(bool useGlobalConfig) { - ViewModel = new InputViewModel(this, useGlobalConfig); // Create new Input Page with the selected input config scope. + if (_subscribedViewModel != null) + { + _subscribedViewModel.PropertyChanged -= ViewModel_OnPropertyChanged; + _subscribedViewModel = null; + } + + InputViewModel newViewModel = new InputViewModel(this, useGlobalConfig); // Create new Input Page with the selected input config scope. + newViewModel.PropertyChanged += ViewModel_OnPropertyChanged; + _subscribedViewModel = newViewModel; + + ViewModel = newViewModel; InitializeComponent(); SetupProfileBoxItemTemplate(); + _isEditingProfileName = false; + UpdateProfileLinkIconVisibility(); + if (VisualRoot is not null) { ViewModel.RetargetKeyboardDriver(this); @@ -232,8 +249,44 @@ namespace Ryujinx.Ava.UI.Views.Input ViewModel?.LoadProfile(); } + private void ViewModel_OnPropertyChanged(object sender, PropertyChangedEventArgs e) + { + if (e.PropertyName == nameof(InputViewModel.IsProfileLinked)) + { + UpdateProfileLinkIconVisibility(); + } + } + + private void ProfileBox_OnGotFocus(object sender, GotFocusEventArgs e) + { + _isEditingProfileName = true; + UpdateProfileLinkIconVisibility(); + } + + private void ProfileBox_OnLostFocus(object sender, RoutedEventArgs e) + { + _isEditingProfileName = false; + UpdateProfileLinkIconVisibility(); + } + + private void UpdateProfileLinkIconVisibility() + { + if (ProfileLinkIcon == null) + { + return; + } + + ProfileLinkIcon.IsVisible = !_isEditingProfileName && (ViewModel?.IsProfileLinked ?? false); + } + public void Dispose() { + if (_subscribedViewModel != null) + { + _subscribedViewModel.PropertyChanged -= ViewModel_OnPropertyChanged; + _subscribedViewModel = null; + } + ViewModel.Dispose(); } }