SettingsWindow.axaml.cs 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  1. using Avalonia;
  2. using Avalonia.Controls;
  3. using Avalonia.Controls.Primitives;
  4. using Avalonia.Data;
  5. using Avalonia.Data.Converters;
  6. using Avalonia.Input;
  7. using Avalonia.Interactivity;
  8. using Avalonia.LogicalTree;
  9. using Avalonia.Markup.Xaml;
  10. using Avalonia.Threading;
  11. using FluentAvalonia.Core;
  12. using FluentAvalonia.UI.Controls;
  13. using Ryujinx.Ava.Common.Locale;
  14. using Ryujinx.Ava.Ui.Controls;
  15. using Ryujinx.Ava.Ui.Models;
  16. using Ryujinx.Ava.Ui.ViewModels;
  17. using Ryujinx.HLE.FileSystem;
  18. using Ryujinx.Input;
  19. using Ryujinx.Input.Assigner;
  20. using System;
  21. using System.Collections.Generic;
  22. using System.Diagnostics;
  23. using System.IO;
  24. using System.Linq;
  25. using System.Threading;
  26. using System.Threading.Tasks;
  27. using TimeZone = Ryujinx.Ava.Ui.Models.TimeZone;
  28. namespace Ryujinx.Ava.Ui.Windows
  29. {
  30. public class SettingsWindow : StyleableWindow
  31. {
  32. private ListBox _gameList;
  33. private TextBox _pathBox;
  34. private AutoCompleteBox _timeZoneBox;
  35. private ControllerSettingsWindow _controllerSettings;
  36. // Pages
  37. private Control _uiPage;
  38. private Control _inputPage;
  39. private Control _hotkeysPage;
  40. private Control _systemPage;
  41. private Control _cpuPage;
  42. private Control _graphicsPage;
  43. private Control _audioPage;
  44. private Control _networkPage;
  45. private Control _loggingPage;
  46. private NavigationView _navPanel;
  47. private ButtonKeyAssigner _currentAssigner;
  48. internal SettingsViewModel ViewModel { get; set; }
  49. public SettingsWindow(VirtualFileSystem virtualFileSystem, ContentManager contentManager)
  50. {
  51. Title = $"Ryujinx {Program.Version} - {LocaleManager.Instance["Settings"]}";
  52. ViewModel = new SettingsViewModel(virtualFileSystem, contentManager, this);
  53. DataContext = ViewModel;
  54. InitializeComponent();
  55. AttachDebugDevTools();
  56. FuncMultiValueConverter<string, string> converter = new(parts => string.Format("{0} {1} {2}", parts.ToArray()));
  57. MultiBinding tzMultiBinding = new() { Converter = converter };
  58. tzMultiBinding.Bindings.Add(new Binding("UtcDifference"));
  59. tzMultiBinding.Bindings.Add(new Binding("Location"));
  60. tzMultiBinding.Bindings.Add(new Binding("Abbreviation"));
  61. _timeZoneBox.ValueMemberBinding = tzMultiBinding;
  62. }
  63. public SettingsWindow()
  64. {
  65. ViewModel = new SettingsViewModel();
  66. DataContext = ViewModel;
  67. InitializeComponent();
  68. AttachDebugDevTools();
  69. }
  70. [Conditional("DEBUG")]
  71. private void AttachDebugDevTools()
  72. {
  73. this.AttachDevTools();
  74. }
  75. private void InitializeComponent()
  76. {
  77. AvaloniaXamlLoader.Load(this);
  78. _pathBox = this.FindControl<TextBox>("PathBox");
  79. _gameList = this.FindControl<ListBox>("GameList");
  80. _timeZoneBox = this.FindControl<AutoCompleteBox>("TimeZoneBox");
  81. _controllerSettings = this.FindControl<ControllerSettingsWindow>("ControllerSettings");
  82. _uiPage = this.FindControl<Control>("UiPage");
  83. _inputPage = this.FindControl<Control>("InputPage");
  84. _hotkeysPage = this.FindControl<Control>("HotkeysPage");
  85. _systemPage = this.FindControl<Control>("SystemPage");
  86. _cpuPage = this.FindControl<Control>("CpuPage");
  87. _graphicsPage = this.FindControl<Control>("GraphicsPage");
  88. _audioPage = this.FindControl<Control>("AudioPage");
  89. _networkPage = this.FindControl<Control>("NetworkPage");
  90. _loggingPage = this.FindControl<Control>("LoggingPage");
  91. var pageGrid = this.FindControl<Grid>("Pages");
  92. pageGrid.Children.Clear();
  93. _navPanel = this.FindControl<NavigationView>("NavPanel");
  94. _navPanel.SelectionChanged += NavPanelOnSelectionChanged;
  95. _navPanel.SelectedItem = _navPanel.MenuItems.ElementAt(0);
  96. }
  97. private void Button_Checked(object sender, RoutedEventArgs e)
  98. {
  99. if (sender is ToggleButton button)
  100. {
  101. if (_currentAssigner != null && button == _currentAssigner.ToggledButton)
  102. {
  103. return;
  104. }
  105. if (_currentAssigner == null && (bool)button.IsChecked)
  106. {
  107. _currentAssigner = new ButtonKeyAssigner(button);
  108. FocusManager.Instance.Focus(this, NavigationMethod.Pointer);
  109. PointerPressed += MouseClick;
  110. IKeyboard keyboard = (IKeyboard)ViewModel.AvaloniaKeyboardDriver.GetGamepad(ViewModel.AvaloniaKeyboardDriver.GamepadsIds[0]);
  111. IButtonAssigner assigner = new KeyboardKeyAssigner(keyboard);
  112. _currentAssigner.GetInputAndAssign(assigner);
  113. }
  114. else
  115. {
  116. if (_currentAssigner != null)
  117. {
  118. ToggleButton oldButton = _currentAssigner.ToggledButton;
  119. _currentAssigner.Cancel();
  120. _currentAssigner = null;
  121. button.IsChecked = false;
  122. }
  123. }
  124. }
  125. }
  126. private void Button_Unchecked(object sender, RoutedEventArgs e)
  127. {
  128. _currentAssigner?.Cancel();
  129. _currentAssigner = null;
  130. }
  131. private void MouseClick(object sender, PointerPressedEventArgs e)
  132. {
  133. bool shouldUnbind = false;
  134. if (e.GetCurrentPoint(this).Properties.IsMiddleButtonPressed)
  135. {
  136. shouldUnbind = true;
  137. }
  138. _currentAssigner?.Cancel(shouldUnbind);
  139. PointerPressed -= MouseClick;
  140. }
  141. private void NavPanelOnSelectionChanged(object sender, NavigationViewSelectionChangedEventArgs e)
  142. {
  143. if (e.SelectedItem is NavigationViewItem navitem)
  144. {
  145. switch (navitem.Tag.ToString())
  146. {
  147. case "UiPage":
  148. _navPanel.Content = _uiPage;
  149. break;
  150. case "InputPage":
  151. _navPanel.Content = _inputPage;
  152. break;
  153. case "HotkeysPage":
  154. _navPanel.Content = _hotkeysPage;
  155. break;
  156. case "SystemPage":
  157. _navPanel.Content = _systemPage;
  158. break;
  159. case "CpuPage":
  160. _navPanel.Content = _cpuPage;
  161. break;
  162. case "GraphicsPage":
  163. _navPanel.Content = _graphicsPage;
  164. break;
  165. case "AudioPage":
  166. _navPanel.Content = _audioPage;
  167. break;
  168. case "NetworkPage":
  169. _navPanel.Content = _networkPage;
  170. break;
  171. case "LoggingPage":
  172. _navPanel.Content = _loggingPage;
  173. break;
  174. }
  175. }
  176. }
  177. private async void AddButton_OnClick(object sender, RoutedEventArgs e)
  178. {
  179. string path = _pathBox.Text;
  180. if (!string.IsNullOrWhiteSpace(path) && Directory.Exists(path) && !ViewModel.GameDirectories.Contains(path))
  181. {
  182. ViewModel.GameDirectories.Add(path);
  183. }
  184. else
  185. {
  186. path = await new OpenFolderDialog().ShowAsync(this);
  187. if (!string.IsNullOrWhiteSpace(path))
  188. {
  189. ViewModel.GameDirectories.Add(path);
  190. }
  191. }
  192. }
  193. private void RemoveButton_OnClick(object sender, RoutedEventArgs e)
  194. {
  195. List<string> selected = new(_gameList.SelectedItems.Cast<string>());
  196. foreach (string path in selected)
  197. {
  198. ViewModel.GameDirectories.Remove(path);
  199. }
  200. }
  201. private void TimeZoneBox_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
  202. {
  203. if (e.AddedItems != null && e.AddedItems.Count > 0)
  204. {
  205. if (e.AddedItems[0] is TimeZone timeZone)
  206. {
  207. e.Handled = true;
  208. ViewModel.ValidateAndSetTimeZone(timeZone.Location);
  209. }
  210. }
  211. }
  212. private void TimeZoneBox_OnTextChanged(object sender, EventArgs e)
  213. {
  214. if (sender is AutoCompleteBox box)
  215. {
  216. if (box.SelectedItem != null && box.SelectedItem is TimeZone timeZone)
  217. {
  218. ViewModel.ValidateAndSetTimeZone(timeZone.Location);
  219. }
  220. }
  221. }
  222. private void SaveButton_Clicked(object sender, RoutedEventArgs e)
  223. {
  224. SaveSettings();
  225. Close();
  226. }
  227. private void CloseButton_Clicked(object sender, RoutedEventArgs e)
  228. {
  229. ViewModel.RevertIfNotSaved();
  230. Close();
  231. }
  232. private void ApplyButton_Clicked(object sender, RoutedEventArgs e)
  233. {
  234. SaveSettings();
  235. }
  236. private void SaveSettings()
  237. {
  238. ViewModel.SaveSettings();
  239. _controllerSettings?.SaveCurrentProfile();
  240. if (Owner is MainWindow window)
  241. {
  242. window.ViewModel.LoadApplications();
  243. }
  244. }
  245. protected override void OnClosed(EventArgs e)
  246. {
  247. _controllerSettings.Dispose();
  248. _currentAssigner?.Cancel();
  249. _currentAssigner = null;
  250. base.OnClosed(e);
  251. }
  252. }
  253. }