diff --git a/src/Ryujinx/AppHost.cs b/src/Ryujinx/AppHost.cs index f143d4e03..b26921e6a 100644 --- a/src/Ryujinx/AppHost.cs +++ b/src/Ryujinx/AppHost.cs @@ -517,7 +517,7 @@ namespace Ryujinx.Ava Device?.System.ChangeDockedModeState(e.NewValue); } - private void UpdateAudioVolumeState(object sender, ReactiveEventArgs e) + public void UpdateAudioVolumeState(object sender, ReactiveEventArgs e) { Device?.SetVolume(e.NewValue); diff --git a/src/Ryujinx/Assets/locales.json b/src/Ryujinx/Assets/locales.json index 27f2b59a5..8cb15fec4 100644 --- a/src/Ryujinx/Assets/locales.json +++ b/src/Ryujinx/Assets/locales.json @@ -3447,6 +3447,156 @@ "zh_TW": "" } }, + { + "ID": "SettingsTabGeneralFocusLossType", + "Translations": { + "ar_SA": "", + "de_DE": "", + "el_GR": "", + "en_US": "On Emulator Focus Lost:", + "es_ES": "", + "fr_FR": "", + "he_IL": "", + "it_IT": "", + "ja_JP": "", + "ko_KR": "", + "no_NO": "", + "pl_PL": "", + "pt_BR": "", + "ru_RU": "", + "sv_SE": "", + "th_TH": "", + "tr_TR": "", + "uk_UA": "", + "zh_CN": "", + "zh_TW": "" + } + }, + { + "ID": "SettingsTabGeneralFocusLossTypeDoNothing", + "Translations": { + "ar_SA": "", + "de_DE": "", + "el_GR": "", + "en_US": "Do Nothing", + "es_ES": "", + "fr_FR": "", + "he_IL": "", + "it_IT": "", + "ja_JP": "", + "ko_KR": "", + "no_NO": "", + "pl_PL": "", + "pt_BR": "", + "ru_RU": "", + "sv_SE": "", + "th_TH": "", + "tr_TR": "", + "uk_UA": "", + "zh_CN": "", + "zh_TW": "" + } + }, + { + "ID": "SettingsTabGeneralFocusLossTypeBlockInput", + "Translations": { + "ar_SA": "", + "de_DE": "", + "el_GR": "", + "en_US": "Block Input", + "es_ES": "", + "fr_FR": "", + "he_IL": "", + "it_IT": "", + "ja_JP": "", + "ko_KR": "", + "no_NO": "", + "pl_PL": "", + "pt_BR": "", + "ru_RU": "", + "sv_SE": "", + "th_TH": "", + "tr_TR": "", + "uk_UA": "", + "zh_CN": "", + "zh_TW": "" + } + }, + { + "ID": "SettingsTabGeneralFocusLossTypeMuteAudio", + "Translations": { + "ar_SA": "", + "de_DE": "", + "el_GR": "", + "en_US": "Mute Volume", + "es_ES": "", + "fr_FR": "", + "he_IL": "", + "it_IT": "", + "ja_JP": "", + "ko_KR": "", + "no_NO": "", + "pl_PL": "", + "pt_BR": "", + "ru_RU": "", + "sv_SE": "", + "th_TH": "", + "tr_TR": "", + "uk_UA": "", + "zh_CN": "", + "zh_TW": "" + } + }, + { + "ID": "SettingsTabGeneralFocusLossTypeBlockInputAndMuteAudio", + "Translations": { + "ar_SA": "", + "de_DE": "", + "el_GR": "", + "en_US": "Block Input & Mute Volume", + "es_ES": "", + "fr_FR": "", + "he_IL": "", + "it_IT": "", + "ja_JP": "", + "ko_KR": "", + "no_NO": "", + "pl_PL": "", + "pt_BR": "", + "ru_RU": "", + "sv_SE": "", + "th_TH": "", + "tr_TR": "", + "uk_UA": "", + "zh_CN": "", + "zh_TW": "" + } + }, + { + "ID": "SettingsTabGeneralFocusLossTypePauseEmulation", + "Translations": { + "ar_SA": "", + "de_DE": "", + "el_GR": "", + "en_US": "Pause Emulation", + "es_ES": "", + "fr_FR": "", + "he_IL": "", + "it_IT": "", + "ja_JP": "", + "ko_KR": "", + "no_NO": "", + "pl_PL": "", + "pt_BR": "", + "ru_RU": "", + "sv_SE": "", + "th_TH": "", + "tr_TR": "", + "uk_UA": "", + "zh_CN": "", + "zh_TW": "" + } + }, { "ID": "SettingsTabGeneralShowConfirmExitDialog", "Translations": { @@ -23923,4 +24073,4 @@ } } ] -} +} \ No newline at end of file diff --git a/src/Ryujinx/Common/ThemeManager.cs b/src/Ryujinx/Common/ThemeManager.cs deleted file mode 100644 index 6da01bfa7..000000000 --- a/src/Ryujinx/Common/ThemeManager.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System; - -namespace Ryujinx.Ava.Common -{ - public static class ThemeManager - { - public static event Action ThemeChanged; - - public static void OnThemeChanged() - { - ThemeChanged?.Invoke(); - } - } -} diff --git a/src/Ryujinx/RyujinxApp.axaml.cs b/src/Ryujinx/RyujinxApp.axaml.cs index 32318776a..90552cd16 100644 --- a/src/Ryujinx/RyujinxApp.axaml.cs +++ b/src/Ryujinx/RyujinxApp.axaml.cs @@ -22,6 +22,8 @@ namespace Ryujinx.Ava { public class RyujinxApp : Application { + public static event Action ThemeChanged; + internal static string FormatTitle(LocaleKeys? windowTitleKey = null, bool includeVersion = true) => windowTitleKey is null ? $"{FullAppName}{(includeVersion ? $" {Program.Version}" : string.Empty)}" @@ -112,7 +114,7 @@ namespace Ryujinx.Ava baseStyle = ConfigurationState.Instance.UI.BaseStyle; } - ThemeManager.OnThemeChanged(); + ThemeChanged?.Invoke(); RequestedThemeVariant = baseStyle switch { diff --git a/src/Ryujinx/UI/ViewModels/AboutWindowViewModel.cs b/src/Ryujinx/UI/ViewModels/AboutWindowViewModel.cs index be0a5d644..7a63c3391 100644 --- a/src/Ryujinx/UI/ViewModels/AboutWindowViewModel.cs +++ b/src/Ryujinx/UI/ViewModels/AboutWindowViewModel.cs @@ -25,10 +25,10 @@ namespace Ryujinx.Ava.UI.ViewModels Version = RyujinxApp.FullAppName + "\n" + Program.Version; UpdateLogoTheme(ConfigurationState.Instance.UI.BaseStyle.Value); - ThemeManager.ThemeChanged += ThemeManager_ThemeChanged; + RyujinxApp.ThemeChanged += Ryujinx_ThemeChanged; } - private void ThemeManager_ThemeChanged() + private void Ryujinx_ThemeChanged() { Dispatcher.UIThread.Post(() => UpdateLogoTheme(ConfigurationState.Instance.UI.BaseStyle.Value)); } @@ -49,7 +49,7 @@ namespace Ryujinx.Ava.UI.ViewModels public void Dispose() { - ThemeManager.ThemeChanged -= ThemeManager_ThemeChanged; + RyujinxApp.ThemeChanged -= Ryujinx_ThemeChanged; GithubLogo.Dispose(); DiscordLogo.Dispose(); diff --git a/src/Ryujinx/UI/ViewModels/SettingsViewModel.cs b/src/Ryujinx/UI/ViewModels/SettingsViewModel.cs index 017d68a28..1b1f8a2a5 100644 --- a/src/Ryujinx/UI/ViewModels/SettingsViewModel.cs +++ b/src/Ryujinx/UI/ViewModels/SettingsViewModel.cs @@ -128,6 +128,8 @@ namespace Ryujinx.Ava.UI.ViewModels public bool EnableMouse { get; set; } public bool DisableInputWhenOutOfFocus { get; set; } + public int FocusLostActionType { get; set; } + public VSyncMode VSyncMode { get => _vSyncMode; @@ -481,6 +483,7 @@ namespace Ryujinx.Ava.UI.ViewModels ShowTitleBar = config.ShowTitleBar; HideCursor = (int)config.HideCursor.Value; UpdateCheckerType = (int)config.UpdateCheckerType.Value; + FocusLostActionType = (int)config.FocusLostActionType.Value; GameDirectories.Clear(); GameDirectories.AddRange(config.UI.GameDirs.Value); @@ -589,6 +592,7 @@ namespace Ryujinx.Ava.UI.ViewModels config.ShowTitleBar.Value = ShowTitleBar; config.HideCursor.Value = (HideCursorMode)HideCursor; config.UpdateCheckerType.Value = (UpdaterType)UpdateCheckerType; + config.FocusLostActionType.Value = (FocusLostType)FocusLostActionType; if (GameDirectoryChanged) { diff --git a/src/Ryujinx/UI/Views/Settings/SettingsUIView.axaml b/src/Ryujinx/UI/Views/Settings/SettingsUIView.axaml index 6aeff31f1..347f0fb51 100644 --- a/src/Ryujinx/UI/Views/Settings/SettingsUIView.axaml +++ b/src/Ryujinx/UI/Views/Settings/SettingsUIView.axaml @@ -37,12 +37,33 @@ - - - + + + + + + + + + + + + + + + + + + + + /// The current version of the file format /// - public const int CurrentVersion = 66; + public const int CurrentVersion = 67; /// /// Version of the configuration file format @@ -171,6 +171,11 @@ namespace Ryujinx.Ava.Utilities.Configuration /// Checks for updates when Ryujinx starts when enabled, either prompting when an update is found or just showing a notification. /// public UpdaterType UpdateCheckerType { get; set; } + + /// + /// How the emulator should behave when you click off/on the window. + /// + public FocusLostType FocusLostActionType { get; set; } /// /// Show "Confirm Exit" Dialog diff --git a/src/Ryujinx/Utilities/Configuration/ConfigurationState.Migration.cs b/src/Ryujinx/Utilities/Configuration/ConfigurationState.Migration.cs index b25de9318..6bca36340 100644 --- a/src/Ryujinx/Utilities/Configuration/ConfigurationState.Migration.cs +++ b/src/Ryujinx/Utilities/Configuration/ConfigurationState.Migration.cs @@ -46,6 +46,7 @@ namespace Ryujinx.Ava.Utilities.Configuration EnableDiscordIntegration.Value = cff.EnableDiscordIntegration; CheckUpdatesOnStart.Value = cff.CheckUpdatesOnStart; UpdateCheckerType.Value = cff.UpdateCheckerType; + FocusLostActionType.Value = cff.FocusLostActionType; ShowConfirmExit.Value = cff.ShowConfirmExit; RememberWindowState.Value = cff.RememberWindowState; ShowTitleBar.Value = cff.ShowTitleBar; @@ -435,7 +436,8 @@ namespace Ryujinx.Ava.Utilities.Configuration (63, static cff => cff.MatchSystemTime = false), (64, static cff => cff.LoggingEnableAvalonia = false), (65, static cff => cff.UpdateCheckerType = cff.CheckUpdatesOnStart ? UpdaterType.PromptAtStartup : UpdaterType.Off), - (66, static cff => cff.DisableInputWhenOutOfFocus = false) + (66, static cff => cff.DisableInputWhenOutOfFocus = false), + (67, static cff => cff.FocusLostActionType = cff.DisableInputWhenOutOfFocus ? FocusLostType.BlockInput : FocusLostType.DoNothing) ); } } diff --git a/src/Ryujinx/Utilities/Configuration/ConfigurationState.Model.cs b/src/Ryujinx/Utilities/Configuration/ConfigurationState.Model.cs index 93496753b..51c40cc99 100644 --- a/src/Ryujinx/Utilities/Configuration/ConfigurationState.Model.cs +++ b/src/Ryujinx/Utilities/Configuration/ConfigurationState.Model.cs @@ -779,6 +779,11 @@ namespace Ryujinx.Ava.Utilities.Configuration /// Checks for updates when Ryujinx starts when enabled, either prompting when an update is found or just showing a notification. /// public ReactiveObject UpdateCheckerType { get; private set; } + + /// + /// How the emulator should behave when you click off/on the window. + /// + public ReactiveObject FocusLostActionType { get; private set; } /// /// Show "Confirm Exit" Dialog @@ -817,6 +822,7 @@ namespace Ryujinx.Ava.Utilities.Configuration EnableDiscordIntegration = new ReactiveObject(); CheckUpdatesOnStart = new ReactiveObject(); UpdateCheckerType = new ReactiveObject(); + FocusLostActionType = new ReactiveObject(); ShowConfirmExit = new ReactiveObject(); RememberWindowState = new ReactiveObject(); ShowTitleBar = new ReactiveObject(); diff --git a/src/Ryujinx/Utilities/Configuration/ConfigurationState.cs b/src/Ryujinx/Utilities/Configuration/ConfigurationState.cs index 0406219f6..774b9217e 100644 --- a/src/Ryujinx/Utilities/Configuration/ConfigurationState.cs +++ b/src/Ryujinx/Utilities/Configuration/ConfigurationState.cs @@ -57,6 +57,7 @@ namespace Ryujinx.Ava.Utilities.Configuration EnableDiscordIntegration = EnableDiscordIntegration, CheckUpdatesOnStart = CheckUpdatesOnStart, UpdateCheckerType = UpdateCheckerType, + FocusLostActionType = FocusLostActionType, ShowConfirmExit = ShowConfirmExit, RememberWindowState = RememberWindowState, ShowTitleBar = ShowTitleBar, @@ -178,6 +179,7 @@ namespace Ryujinx.Ava.Utilities.Configuration System.EnableDockedMode.Value = true; EnableDiscordIntegration.Value = true; UpdateCheckerType.Value = UpdaterType.PromptAtStartup; + FocusLostActionType.Value = FocusLostType.DoNothing; ShowConfirmExit.Value = true; RememberWindowState.Value = true; ShowTitleBar.Value = !OperatingSystem.IsWindows(); diff --git a/src/Ryujinx/Utilities/Configuration/UI/FocusLostType.cs b/src/Ryujinx/Utilities/Configuration/UI/FocusLostType.cs new file mode 100644 index 000000000..eea588539 --- /dev/null +++ b/src/Ryujinx/Utilities/Configuration/UI/FocusLostType.cs @@ -0,0 +1,15 @@ +using Ryujinx.Common.Utilities; +using System.Text.Json.Serialization; + +namespace Ryujinx.Ava.Utilities.Configuration.UI +{ + [JsonConverter(typeof(TypedStringEnumConverter))] + public enum FocusLostType + { + DoNothing, + BlockInput, + MuteAudio, + BlockInputAndMuteAudio, + PauseEmulation + } +}