diff --git a/Ryujinx.Ava/UI/Models/TimeZone.cs b/Ryujinx.Ava/UI/Models/TimeZone.cs index cb6cc2fdc..e897606f7 100644 --- a/Ryujinx.Ava/UI/Models/TimeZone.cs +++ b/Ryujinx.Ava/UI/Models/TimeZone.cs @@ -1,6 +1,6 @@ namespace Ryujinx.Ava.UI.Models { - internal class TimeZone + public class TimeZone { public TimeZone(string utcDifference, string location, string abbreviation) { diff --git a/Ryujinx.Ava/UI/ViewModels/SettingsViewModel.cs b/Ryujinx.Ava/UI/ViewModels/SettingsViewModel.cs index de1bde46b..ad3c8cff7 100644 --- a/Ryujinx.Ava/UI/ViewModels/SettingsViewModel.cs +++ b/Ryujinx.Ava/UI/ViewModels/SettingsViewModel.cs @@ -1,4 +1,3 @@ -using Avalonia; using Avalonia.Collections; using Avalonia.Controls; using Avalonia.Threading; @@ -8,8 +7,6 @@ using Ryujinx.Audio.Backends.OpenAL; using Ryujinx.Audio.Backends.SDL2; using Ryujinx.Audio.Backends.SoundIo; using Ryujinx.Ava.Common.Locale; -using Ryujinx.Ava.Input; -using Ryujinx.Ava.UI.Controls; using Ryujinx.Ava.UI.Helpers; using Ryujinx.Ava.UI.Windows; using Ryujinx.Common.Configuration; @@ -19,7 +16,6 @@ using Ryujinx.Common.Logging; using Ryujinx.Graphics.Vulkan; using Ryujinx.HLE.FileSystem; using Ryujinx.HLE.HOS.Services.Time.TimeZone; -using Ryujinx.Input; using Ryujinx.Ui.Common.Configuration; using Ryujinx.Ui.Common.Configuration.System; using System; @@ -30,11 +26,10 @@ using TimeZone = Ryujinx.Ava.UI.Models.TimeZone; namespace Ryujinx.Ava.UI.ViewModels { - internal class SettingsViewModel : BaseModel + public class SettingsViewModel : BaseModel { private readonly VirtualFileSystem _virtualFileSystem; private readonly ContentManager _contentManager; - private readonly StyleableWindow _owner; private TimeZoneContentManager _timeZoneContentManager; private readonly List _validTzRegions; @@ -44,10 +39,14 @@ namespace Ryujinx.Ava.UI.ViewModels private int _graphicsBackendMultithreadingIndex; private float _volume; private bool _isVulkanAvailable = true; - private bool _directoryChanged = false; - private List _gpuIds = new List(); + private bool _directoryChanged; + private List _gpuIds = new(); private KeyboardHotkeys _keyboardHotkeys; private int _graphicsBackendIndex; + private string _customThemePath; + + public event Action CloseWindow; + public event Action SaveSettingsEvent; public int ResolutionScale { @@ -67,19 +66,19 @@ namespace Ryujinx.Ava.UI.ViewModels { _graphicsBackendMultithreadingIndex = value; - if (_owner != null) + if (_graphicsBackendMultithreadingIndex != (int)ConfigurationState.Instance.Graphics.BackendThreading.Value) { - if (_graphicsBackendMultithreadingIndex != (int)ConfigurationState.Instance.Graphics.BackendThreading.Value) + async void Action() { - Dispatcher.UIThread.Post(async () => - { - await ContentDialogHelper.CreateInfoDialog(LocaleManager.Instance["DialogSettingsBackendThreadingWarningMessage"], - "", - "", - LocaleManager.Instance["InputDialogOk"], - LocaleManager.Instance["DialogSettingsBackendThreadingWarningTitle"]); - }); + await ContentDialogHelper.CreateInfoDialog( + LocaleManager.Instance["DialogSettingsBackendThreadingWarningMessage"], + "", + "", + LocaleManager.Instance["InputDialogOk"], + LocaleManager.Instance["DialogSettingsBackendThreadingWarningTitle"]); } + + Dispatcher.UIThread.Post(Action); } OnPropertyChanged(); @@ -160,7 +159,19 @@ namespace Ryujinx.Ava.UI.ViewModels public string TimeZone { get; set; } public string ShaderDumpPath { get; set; } - public string CustomThemePath { get; set; } + + public string CustomThemePath + { + get + { + return _customThemePath; + } + set + { + _customThemePath = value; + OnPropertyChanged(); + } + } public int Language { get; set; } public int Region { get; set; } @@ -191,7 +202,7 @@ namespace Ryujinx.Ava.UI.ViewModels { _volume = value; - ConfigurationState.Instance.System.AudioVolume.Value = (float)(_volume / 100); + ConfigurationState.Instance.System.AudioVolume.Value = _volume / 100; OnPropertyChanged(); } @@ -213,18 +224,14 @@ namespace Ryujinx.Ava.UI.ViewModels OnPropertyChanged(); } } - - public IGamepadDriver AvaloniaKeyboardDriver { get; } - - public SettingsViewModel(VirtualFileSystem virtualFileSystem, ContentManager contentManager, StyleableWindow owner) : this() + + public SettingsViewModel(VirtualFileSystem virtualFileSystem, ContentManager contentManager) : this() { _virtualFileSystem = virtualFileSystem; _contentManager = contentManager; - _owner = owner; if (Program.PreviewerDetached) { LoadTimeZones(); - AvaloniaKeyboardDriver = new AvaloniaKeyboardDriver(owner); } } @@ -251,10 +258,10 @@ namespace Ryujinx.Ava.UI.ViewModels IsSDL2Enabled = SDL2HardwareDeviceDriver.IsSupported; } - private unsafe void LoadAvailableGpus() + private void LoadAvailableGpus() { _gpuIds = new List(); - List names = new List(); + List names = new(); var devices = VulkanRenderer.GetPhysicalDevices(); if (devices.Length == 0) @@ -272,7 +279,7 @@ namespace Ryujinx.Ava.UI.ViewModels } AvailableGpus.Clear(); - AvailableGpus.AddRange(names.Select(x => new ComboBoxItem() { Content = x })); + AvailableGpus.AddRange(names.Select(x => new ComboBoxItem { Content = x })); } public void LoadTimeZones() @@ -302,25 +309,6 @@ namespace Ryujinx.Ava.UI.ViewModels } } - public async void BrowseTheme() - { - var dialog = new OpenFileDialog() - { - Title = LocaleManager.Instance["SettingsSelectThemeFileDialogTitle"], - AllowMultiple = false - }; - - dialog.Filters.Add(new FileDialogFilter() { Extensions = { "xaml" }, Name = LocaleManager.Instance["SettingsXamlThemeFile"] }); - - var file = await dialog.ShowAsync(_owner); - - if (file != null && file.Length > 0) - { - CustomThemePath = file[0]; - OnPropertyChanged(nameof(CustomThemePath)); - } - } - public void LoadCurrentConfiguration() { ConfigurationState config = ConfigurationState.Instance; @@ -478,15 +466,7 @@ namespace Ryujinx.Ava.UI.ViewModels MainWindow.UpdateGraphicsConfig(); - if (_owner is SettingsWindow owner) - { - owner.ControllerSettings?.SaveCurrentProfile(); - } - - if (_owner.Owner is MainWindow window && _directoryChanged) - { - window.ViewModel.LoadApplications(); - } + SaveSettingsEvent?.Invoke(); _directoryChanged = false; } @@ -504,13 +484,13 @@ namespace Ryujinx.Ava.UI.ViewModels public void OkButton() { SaveSettings(); - _owner.Close(); + CloseWindow?.Invoke(); } public void CancelButton() { RevertIfNotSaved(); - _owner.Close(); + CloseWindow?.Invoke(); } } } \ No newline at end of file diff --git a/Ryujinx.Ava/UI/Views/Settings/SettingsAudioView.axaml b/Ryujinx.Ava/UI/Views/Settings/SettingsAudioView.axaml new file mode 100644 index 000000000..352833534 --- /dev/null +++ b/Ryujinx.Ava/UI/Views/Settings/SettingsAudioView.axaml @@ -0,0 +1,81 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Ryujinx.Ava/UI/Views/Settings/SettingsAudioView.axaml.cs b/Ryujinx.Ava/UI/Views/Settings/SettingsAudioView.axaml.cs new file mode 100644 index 000000000..cc2347b3e --- /dev/null +++ b/Ryujinx.Ava/UI/Views/Settings/SettingsAudioView.axaml.cs @@ -0,0 +1,11 @@ +using Avalonia.Controls; + +namespace Ryujinx.Ava.UI.Views.Settings; + +public partial class SettingsAudioView : UserControl +{ + public SettingsAudioView() + { + InitializeComponent(); + } +} \ No newline at end of file diff --git a/Ryujinx.Ava/UI/Views/Settings/SettingsCPUView.axaml b/Ryujinx.Ava/UI/Views/Settings/SettingsCPUView.axaml new file mode 100644 index 000000000..a0cf34529 --- /dev/null +++ b/Ryujinx.Ava/UI/Views/Settings/SettingsCPUView.axaml @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Ryujinx.Ava/UI/Views/Settings/SettingsCPUView.axaml.cs b/Ryujinx.Ava/UI/Views/Settings/SettingsCPUView.axaml.cs new file mode 100644 index 000000000..443c2061b --- /dev/null +++ b/Ryujinx.Ava/UI/Views/Settings/SettingsCPUView.axaml.cs @@ -0,0 +1,11 @@ +using Avalonia.Controls; + +namespace Ryujinx.Ava.UI.Views.Settings; + +public partial class SettingsCPUView : UserControl +{ + public SettingsCPUView() + { + InitializeComponent(); + } +} \ No newline at end of file diff --git a/Ryujinx.Ava/UI/Views/Settings/SettingsGraphicsView.axaml b/Ryujinx.Ava/UI/Views/Settings/SettingsGraphicsView.axaml new file mode 100644 index 000000000..1f65155a2 --- /dev/null +++ b/Ryujinx.Ava/UI/Views/Settings/SettingsGraphicsView.axaml @@ -0,0 +1,218 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Ryujinx.Ava/UI/Views/Settings/SettingsGraphicsView.axaml.cs b/Ryujinx.Ava/UI/Views/Settings/SettingsGraphicsView.axaml.cs new file mode 100644 index 000000000..7f1d84db7 --- /dev/null +++ b/Ryujinx.Ava/UI/Views/Settings/SettingsGraphicsView.axaml.cs @@ -0,0 +1,11 @@ +using Avalonia.Controls; + +namespace Ryujinx.Ava.UI.Views.Settings; + +public partial class SettingsGraphicsView : UserControl +{ + public SettingsGraphicsView() + { + InitializeComponent(); + } +} \ No newline at end of file diff --git a/Ryujinx.Ava/UI/Views/Settings/SettingsHotkeysView.axaml b/Ryujinx.Ava/UI/Views/Settings/SettingsHotkeysView.axaml new file mode 100644 index 000000000..361125bfe --- /dev/null +++ b/Ryujinx.Ava/UI/Views/Settings/SettingsHotkeysView.axaml @@ -0,0 +1,104 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Ryujinx.Ava/UI/Views/Settings/SettingsHotkeysView.axaml.cs b/Ryujinx.Ava/UI/Views/Settings/SettingsHotkeysView.axaml.cs new file mode 100644 index 000000000..d87631b20 --- /dev/null +++ b/Ryujinx.Ava/UI/Views/Settings/SettingsHotkeysView.axaml.cs @@ -0,0 +1,80 @@ +using Avalonia.Controls; +using Avalonia.Controls.Primitives; +using Avalonia.Input; +using Avalonia.Interactivity; +using Ryujinx.Ava.Input; +using Ryujinx.Ava.UI.Helpers; +using Ryujinx.Input; +using Ryujinx.Input.Assigner; + +namespace Ryujinx.Ava.UI.Views.Settings; + +public partial class SettingsHotkeysView : UserControl +{ + private ButtonKeyAssigner _currentAssigner; + private IGamepadDriver AvaloniaKeyboardDriver; + + public SettingsHotkeysView() + { + InitializeComponent(); + AvaloniaKeyboardDriver = new AvaloniaKeyboardDriver(this); + } + + private void MouseClick(object sender, PointerPressedEventArgs e) + { + bool shouldUnbind = e.GetCurrentPoint(this).Properties.IsMiddleButtonPressed; + + _currentAssigner?.Cancel(shouldUnbind); + + PointerPressed -= MouseClick; + } + + private void Button_Checked(object sender, RoutedEventArgs e) + { + if (sender is ToggleButton button) + { + if (_currentAssigner != null && button == _currentAssigner.ToggledButton) + { + return; + } + + if (_currentAssigner == null && button.IsChecked != null && (bool)button.IsChecked) + { + _currentAssigner = new ButtonKeyAssigner(button); + + FocusManager.Instance?.Focus(this, NavigationMethod.Pointer); + + PointerPressed += MouseClick; + + var keyboard = (IKeyboard)AvaloniaKeyboardDriver.GetGamepad(AvaloniaKeyboardDriver.GamepadsIds[0]); + IButtonAssigner assigner = new KeyboardKeyAssigner(keyboard); + + _currentAssigner.GetInputAndAssign(assigner); + } + else + { + if (_currentAssigner != null) + { + ToggleButton oldButton = _currentAssigner.ToggledButton; + + _currentAssigner.Cancel(); + _currentAssigner = null; + + button.IsChecked = false; + } + } + } + } + + private void Button_Unchecked(object sender, RoutedEventArgs e) + { + _currentAssigner?.Cancel(); + _currentAssigner = null; + } + + public void Dispose() + { + _currentAssigner?.Cancel(); + _currentAssigner = null; + } +} \ No newline at end of file diff --git a/Ryujinx.Ava/UI/Views/Settings/SettingsInputView.axaml b/Ryujinx.Ava/UI/Views/Settings/SettingsInputView.axaml new file mode 100644 index 000000000..1c774bdad --- /dev/null +++ b/Ryujinx.Ava/UI/Views/Settings/SettingsInputView.axaml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Ryujinx.Ava/UI/Views/Settings/SettingsInputView.axaml.cs b/Ryujinx.Ava/UI/Views/Settings/SettingsInputView.axaml.cs new file mode 100644 index 000000000..198b0a09f --- /dev/null +++ b/Ryujinx.Ava/UI/Views/Settings/SettingsInputView.axaml.cs @@ -0,0 +1,16 @@ +using Avalonia.Controls; + +namespace Ryujinx.Ava.UI.Views.Settings; + +public partial class SettingsInputView : UserControl +{ + public SettingsInputView() + { + InitializeComponent(); + } + + public void Dispose() + { + ControllerSettings.Dispose(); + } +} \ No newline at end of file diff --git a/Ryujinx.Ava/UI/Views/Settings/SettingsLoggingView.axaml b/Ryujinx.Ava/UI/Views/Settings/SettingsLoggingView.axaml new file mode 100644 index 000000000..2163dcdac --- /dev/null +++ b/Ryujinx.Ava/UI/Views/Settings/SettingsLoggingView.axaml @@ -0,0 +1,118 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Ryujinx.Ava/UI/Views/Settings/SettingsLoggingView.axaml.cs b/Ryujinx.Ava/UI/Views/Settings/SettingsLoggingView.axaml.cs new file mode 100644 index 000000000..3b440a897 --- /dev/null +++ b/Ryujinx.Ava/UI/Views/Settings/SettingsLoggingView.axaml.cs @@ -0,0 +1,11 @@ +using Avalonia.Controls; + +namespace Ryujinx.Ava.UI.Views.Settings; + +public partial class SettingsLoggingView : UserControl +{ + public SettingsLoggingView() + { + InitializeComponent(); + } +} \ No newline at end of file diff --git a/Ryujinx.Ava/UI/Views/Settings/SettingsNetworkView.axaml b/Ryujinx.Ava/UI/Views/Settings/SettingsNetworkView.axaml new file mode 100644 index 000000000..8efd367dd --- /dev/null +++ b/Ryujinx.Ava/UI/Views/Settings/SettingsNetworkView.axaml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Ryujinx.Ava/UI/Views/Settings/SettingsNetworkView.axaml.cs b/Ryujinx.Ava/UI/Views/Settings/SettingsNetworkView.axaml.cs new file mode 100644 index 000000000..7ff345b7c --- /dev/null +++ b/Ryujinx.Ava/UI/Views/Settings/SettingsNetworkView.axaml.cs @@ -0,0 +1,11 @@ +using Avalonia.Controls; + +namespace Ryujinx.Ava.UI.Views.Settings; + +public partial class SettingsNetworkView : UserControl +{ + public SettingsNetworkView() + { + InitializeComponent(); + } +} \ No newline at end of file diff --git a/Ryujinx.Ava/UI/Views/Settings/SettingsSystemView.axaml b/Ryujinx.Ava/UI/Views/Settings/SettingsSystemView.axaml new file mode 100644 index 000000000..ddcca39cb --- /dev/null +++ b/Ryujinx.Ava/UI/Views/Settings/SettingsSystemView.axaml @@ -0,0 +1,195 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Ryujinx.Ava/UI/Views/Settings/SettingsSystemView.axaml.cs b/Ryujinx.Ava/UI/Views/Settings/SettingsSystemView.axaml.cs new file mode 100644 index 000000000..d8435438b --- /dev/null +++ b/Ryujinx.Ava/UI/Views/Settings/SettingsSystemView.axaml.cs @@ -0,0 +1,51 @@ +using Avalonia.Controls; +using Avalonia.Data; +using Avalonia.Data.Converters; +using Ryujinx.Ava.UI.ViewModels; +using System; +using System.Linq; +using TimeZone = Ryujinx.Ava.UI.Models.TimeZone; + +namespace Ryujinx.Ava.UI.Views.Settings; + +public partial class SettingsSystemView : UserControl +{ + public SettingsViewModel ViewModel; + + public SettingsSystemView() + { + InitializeComponent(); + + FuncMultiValueConverter converter = new(parts => string.Format("{0} {1} {2}", parts.ToArray()).Trim()); + MultiBinding tzMultiBinding = new() { Converter = converter }; + tzMultiBinding.Bindings.Add(new Binding("UtcDifference")); + tzMultiBinding.Bindings.Add(new Binding("Location")); + tzMultiBinding.Bindings.Add(new Binding("Abbreviation")); + + TimeZoneBox.ValueMemberBinding = tzMultiBinding; + } + + private void TimeZoneBox_OnSelectionChanged(object sender, SelectionChangedEventArgs e) + { + if (e.AddedItems != null && e.AddedItems.Count > 0) + { + if (e.AddedItems[0] is TimeZone timeZone) + { + e.Handled = true; + + ViewModel.ValidateAndSetTimeZone(timeZone.Location); + } + } + } + + private void TimeZoneBox_OnTextChanged(object sender, EventArgs e) + { + if (sender is AutoCompleteBox box) + { + if (box.SelectedItem != null && box.SelectedItem is TimeZone timeZone) + { + ViewModel.ValidateAndSetTimeZone(timeZone.Location); + } + } + } +} \ No newline at end of file diff --git a/Ryujinx.Ava/UI/Views/Settings/SettingsUIView.axaml b/Ryujinx.Ava/UI/Views/Settings/SettingsUIView.axaml new file mode 100644 index 000000000..61b6c4335 --- /dev/null +++ b/Ryujinx.Ava/UI/Views/Settings/SettingsUIView.axaml @@ -0,0 +1,156 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - -