MainMenuBarView.axaml.cs 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. using Avalonia;
  2. using Avalonia.Controls;
  3. using Avalonia.Interactivity;
  4. using Avalonia.Threading;
  5. using Gommon;
  6. using Ryujinx.Ava.Common.Locale;
  7. using Ryujinx.Ava.UI.Helpers;
  8. using Ryujinx.Ava.UI.ViewModels;
  9. using Ryujinx.Ava.UI.Windows;
  10. using Ryujinx.Ava.Utilities;
  11. using Ryujinx.Ava.Utilities.Compat;
  12. using Ryujinx.Ava.Utilities.Configuration;
  13. using Ryujinx.Common;
  14. using Ryujinx.Common.Helper;
  15. using Ryujinx.Common.Utilities;
  16. using Ryujinx.HLE.HOS.Services.Nfc.AmiiboDecryption;
  17. using System;
  18. using System.Collections.Generic;
  19. using System.Linq;
  20. namespace Ryujinx.Ava.UI.Views.Main
  21. {
  22. public partial class MainMenuBarView : UserControl
  23. {
  24. public MainWindow Window { get; private set; }
  25. public MainWindowViewModel ViewModel { get; private set; }
  26. public MainMenuBarView()
  27. {
  28. InitializeComponent();
  29. RyuLogo.IsVisible = !ConfigurationState.Instance.ShowTitleBar;
  30. RyuLogo.Source = MainWindowViewModel.IconBitmap;
  31. ToggleFileTypesMenuItem.ItemsSource = GenerateToggleFileTypeItems();
  32. ChangeLanguageMenuItem.ItemsSource = GenerateLanguageMenuItems();
  33. }
  34. private CheckBox[] GenerateToggleFileTypeItems() =>
  35. Enum.GetValues<FileTypes>()
  36. .Select(it => (FileName: Enum.GetName(it)!, FileType: it))
  37. .Select(it =>
  38. new CheckBox
  39. {
  40. Content = $".{it.FileName}",
  41. IsChecked = it.FileType.GetConfigValue(ConfigurationState.Instance.UI.ShownFileTypes),
  42. Command = MiniCommand.Create(() => Window.ToggleFileType(it.FileName))
  43. }
  44. ).ToArray();
  45. private static MenuItem[] GenerateLanguageMenuItems()
  46. {
  47. List<MenuItem> menuItems = new();
  48. string localePath = "Ryujinx/Assets/locales.json";
  49. string languageJson = EmbeddedResources.ReadAllText(localePath);
  50. LocalesJson locales = JsonHelper.Deserialize(languageJson, LocalesJsonContext.Default.LocalesJson);
  51. foreach (string language in locales.Languages)
  52. {
  53. int index = locales.Locales.FindIndex(x => x.ID == "Language");
  54. string languageName;
  55. if (index == -1)
  56. {
  57. languageName = language;
  58. }
  59. else
  60. {
  61. languageName = locales.Locales[index].Translations[language] == "" ? language : locales.Locales[index].Translations[language];
  62. }
  63. MenuItem menuItem = new()
  64. {
  65. Padding = new Thickness(10, 0, 0, 0),
  66. Header = " " + languageName,
  67. Command = MiniCommand.Create(() => MainWindowViewModel.ChangeLanguage(language))
  68. };
  69. menuItems.Add(menuItem);
  70. }
  71. return menuItems.ToArray();
  72. }
  73. protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
  74. {
  75. base.OnAttachedToVisualTree(e);
  76. if (VisualRoot is MainWindow window)
  77. {
  78. Window = window;
  79. DataContext = ViewModel = window.ViewModel;
  80. }
  81. }
  82. private async void StopEmulation_Click(object sender, RoutedEventArgs e)
  83. {
  84. await ViewModel.AppHost?.ShowExitPrompt().OrCompleted()!;
  85. }
  86. private void PauseEmulation_Click(object sender, RoutedEventArgs e)
  87. {
  88. ViewModel.AppHost?.Pause();
  89. }
  90. private void ResumeEmulation_Click(object sender, RoutedEventArgs e)
  91. {
  92. ViewModel.AppHost?.Resume();
  93. }
  94. public async void OpenSettings(object sender, RoutedEventArgs e)
  95. {
  96. Window.SettingsWindow = new(Window.VirtualFileSystem, Window.ContentManager);
  97. await Window.SettingsWindow.ShowDialog(Window);
  98. Window.SettingsWindow = null;
  99. ViewModel.LoadConfigurableHotKeys();
  100. }
  101. public static readonly AppletMetadata MiiApplet = new("miiEdit", 0x0100000000001009);
  102. public async void OpenMiiApplet(object sender, RoutedEventArgs e)
  103. {
  104. if (MiiApplet.CanStart(ViewModel.ContentManager, out var appData, out var nacpData))
  105. {
  106. await ViewModel.LoadApplication(appData, ViewModel.IsFullScreen || ViewModel.StartGamesInFullscreen, nacpData);
  107. }
  108. }
  109. public async void OpenAmiiboWindow(object sender, RoutedEventArgs e)
  110. => await ViewModel.OpenAmiiboWindow();
  111. public async void OpenBinFile(object sender, RoutedEventArgs e)
  112. => await ViewModel.OpenBinFile();
  113. public async void OpenCheatManagerForCurrentApp(object sender, RoutedEventArgs e)
  114. {
  115. if (!ViewModel.IsGameRunning)
  116. return;
  117. string name = ViewModel.AppHost.Device.Processes.ActiveApplication.ApplicationControlProperties.Title[(int)ViewModel.AppHost.Device.System.State.DesiredTitleLanguage].NameString.ToString();
  118. await new CheatWindow(
  119. Window.VirtualFileSystem,
  120. ViewModel.AppHost.Device.Processes.ActiveApplication.ProgramIdText,
  121. name,
  122. ViewModel.SelectedApplication.Path).ShowDialog(Window);
  123. ViewModel.AppHost.Device.EnableCheats();
  124. }
  125. private void ScanAmiiboMenuItem_AttachedToVisualTree(object sender, VisualTreeAttachmentEventArgs e)
  126. {
  127. if (sender is MenuItem)
  128. ViewModel.IsAmiiboRequested = ViewModel.AppHost.Device.System.SearchingForAmiibo(out _);
  129. }
  130. private void ScanBinAmiiboMenuItem_AttachedToVisualTree(object sender, VisualTreeAttachmentEventArgs e)
  131. {
  132. if (sender is MenuItem)
  133. ViewModel.IsAmiiboBinRequested = ViewModel.IsAmiiboRequested && AmiiboBinReader.HasAmiiboKeyFile;
  134. }
  135. private async void InstallFileTypes_Click(object sender, RoutedEventArgs e)
  136. {
  137. ViewModel.AreMimeTypesRegistered = FileAssociationHelper.Install();
  138. if (ViewModel.AreMimeTypesRegistered)
  139. await ContentDialogHelper.CreateInfoDialog(LocaleManager.Instance[LocaleKeys.DialogInstallFileTypesSuccessMessage], string.Empty, LocaleManager.Instance[LocaleKeys.InputDialogOk], string.Empty, string.Empty);
  140. else
  141. await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogInstallFileTypesErrorMessage]);
  142. }
  143. private async void UninstallFileTypes_Click(object sender, RoutedEventArgs e)
  144. {
  145. ViewModel.AreMimeTypesRegistered = !FileAssociationHelper.Uninstall();
  146. if (!ViewModel.AreMimeTypesRegistered)
  147. await ContentDialogHelper.CreateInfoDialog(LocaleManager.Instance[LocaleKeys.DialogUninstallFileTypesSuccessMessage], string.Empty, LocaleManager.Instance[LocaleKeys.InputDialogOk], string.Empty, string.Empty);
  148. else
  149. await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogUninstallFileTypesErrorMessage]);
  150. }
  151. private async void ChangeWindowSize_Click(object sender, RoutedEventArgs e)
  152. {
  153. if (sender is not MenuItem { Tag: string resolution })
  154. return;
  155. (int resolutionWidth, int resolutionHeight) = resolution.Split(' ', 2)
  156. .Into(parts =>
  157. (int.Parse(parts[0]), int.Parse(parts[1]))
  158. );
  159. // Correctly size window when 'TitleBar' is enabled (Nov. 14, 2024)
  160. double barsHeight = ((Window.StatusBarHeight + Window.MenuBarHeight) +
  161. (ConfigurationState.Instance.ShowTitleBar ? (int)Window.TitleBar.Height : 0));
  162. double windowWidthScaled = (resolutionWidth * Program.WindowScaleFactor);
  163. double windowHeightScaled = ((resolutionHeight + barsHeight) * Program.WindowScaleFactor);
  164. await Dispatcher.UIThread.InvokeAsync(() =>
  165. {
  166. ViewModel.WindowState = WindowState.Normal;
  167. Window.Arrange(new Rect(Window.Position.X, Window.Position.Y, windowWidthScaled, windowHeightScaled));
  168. });
  169. }
  170. public async void CheckForUpdates(object sender, RoutedEventArgs e)
  171. {
  172. if (Updater.CanUpdate(true))
  173. await Updater.BeginUpdateAsync(true);
  174. }
  175. private void MenuItem_OnClick(object sender, RoutedEventArgs e)
  176. {
  177. if (sender is MenuItem { Tag: string url })
  178. OpenHelper.OpenUrl(url);
  179. }
  180. public async void OpenXCITrimmerWindow(object sender, RoutedEventArgs e) => await XCITrimmerWindow.Show(ViewModel);
  181. public async void OpenAboutWindow(object sender, RoutedEventArgs e) => await AboutWindow.Show();
  182. public void CloseWindow(object sender, RoutedEventArgs e) => Window.Close();
  183. private async void OpenCompatibilityList(object sender, RoutedEventArgs e) => await CompatibilityList.Show();
  184. }
  185. }