diff --git a/src/Ryujinx/UI/Controls/RyujinxLogo.cs b/src/Ryujinx/UI/Controls/RyujinxLogo.cs index e1908fc2b..972f8f4e0 100644 --- a/src/Ryujinx/UI/Controls/RyujinxLogo.cs +++ b/src/Ryujinx/UI/Controls/RyujinxLogo.cs @@ -1,28 +1,84 @@ using Avalonia; using Avalonia.Controls; using Avalonia.Media.Imaging; +using Ryujinx.Ava.Common.Models; using Ryujinx.Ava.Systems.Configuration; -using Ryujinx.Ava.UI.ViewModels; -using System.Reflection; +using Ryujinx.Common; +using Svg.Skia; +using System; +using System.IO; +using System.Linq; namespace Ryujinx.Ava.UI.Controls { public class RyujinxLogo : Image { - // The UI specifically uses a thicker bordered variant of the icon to avoid crunching out the border at lower resolutions. - // For an example of this, download canary 1.2.95, then open the settings menu, and look at the icon in the top-left. - // The border gets reduced to colored pixels in the 4 corners. - public static readonly Bitmap Bitmap = - new(Assembly.GetAssembly(typeof(MainWindowViewModel))! - .GetManifestResourceStream("Ryujinx.Assets.UIImages.Logo_Ryujinx_AntiAlias.png")!); + public static ReactiveObject CurrentLogoBitmap { get; private set; } = new(); public RyujinxLogo() { Margin = new Thickness(7, 7, 7, 0); Height = 25; Width = 25; - Source = Bitmap; + Source = CurrentLogoBitmap.Value; IsVisible = !ConfigurationState.Instance.ShowOldUI; + ConfigurationState.Instance.UI.SelectedWindowIcon.Event += WindowIconChanged_Event; } + + public static void RefreshAppIconFromSettings() + { + SetNewAppIcon(ConfigurationState.Instance.UI.SelectedWindowIcon.Value); + } + + private static void SetNewAppIcon(string newIconName) + { + string defaultIconName = "Bordered Ryupride"; + if (string.IsNullOrEmpty(newIconName)) + { + SetDefaultAppIcon(defaultIconName); + } + + ApplicationIcon selectedIcon = RyujinxApp.AvailableApplicationIcons.FirstOrDefault(x => x.Name == newIconName); + if (selectedIcon == null) + { + // Always try to fallback to "Bordered Ryupride" as a default + // If not found, fallback to first found icon + if (newIconName != defaultIconName) + { + SetDefaultAppIcon(defaultIconName); + return; + } + + if (RyujinxApp.AvailableApplicationIcons.Count > 0) + { + SetDefaultAppIcon(RyujinxApp.AvailableApplicationIcons.First().Name); + return; + } + } + + Stream activeIconStream = EmbeddedResources.GetStream(selectedIcon.FullPath); + if (activeIconStream != null) + { + // SVG files need to be converted to an image first + if (selectedIcon.FullPath.EndsWith(".svg", StringComparison.OrdinalIgnoreCase)) + { + // TODO: Convert SVG to a bitmap + using SKSvg svg = new(); + } + else + { + CurrentLogoBitmap.Value = new Bitmap(activeIconStream); + } + } + } + + private static void SetDefaultAppIcon(string defaultIconName) + { + // Doing this triggers the WindowIconChanged_Event, which will then + // call SetNewAppIcon again + ConfigurationState.Instance.UI.SelectedWindowIcon.Value = defaultIconName; + } + + private void WindowIconChanged_Event(object _, ReactiveEventArgs rArgs) => SetNewAppIcon(rArgs.NewValue); } } diff --git a/src/Ryujinx/UI/RyujinxApp.axaml.cs b/src/Ryujinx/UI/RyujinxApp.axaml.cs index 0ae1a964e..714f7703a 100644 --- a/src/Ryujinx/UI/RyujinxApp.axaml.cs +++ b/src/Ryujinx/UI/RyujinxApp.axaml.cs @@ -2,7 +2,6 @@ using Avalonia; using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Input.Platform; using Avalonia.Markup.Xaml; -using Avalonia.Media.Imaging; using Avalonia.Platform; using Avalonia.Styling; using Avalonia.Threading; @@ -11,6 +10,7 @@ using Gommon; using Ryujinx.Ava.Common.Locale; using Ryujinx.Ava.Common.Models; using Ryujinx.Ava.Systems.Configuration; +using Ryujinx.Ava.UI.Controls; using Ryujinx.Ava.UI.Helpers; using Ryujinx.Ava.UI.Views.Dialog; using Ryujinx.Ava.UI.Windows; @@ -58,6 +58,7 @@ namespace Ryujinx.Ava Name = FormatTitle(); RetrieveAvailableAppIcons(); + RyujinxLogo.RefreshAppIconFromSettings(); AvaloniaXamlLoader.Load(this); @@ -80,9 +81,6 @@ namespace Ryujinx.Ava { ApplyConfiguredTheme(ConfigurationState.Instance.UI.BaseStyle); ConfigurationState.Instance.UI.BaseStyle.Event += ThemeChanged_Event; - - UpdateAppIcon(ConfigurationState.Instance.UI.SelectedWindowIcon); - ConfigurationState.Instance.UI.SelectedWindowIcon.Event += WindowIconChanged_Event; } } @@ -182,28 +180,5 @@ namespace Ryujinx.Ava }); } } - - public static void UpdateAppIcon(string newIconName) - { - if (newIconName.IsNullOrEmpty()) - { - newIconName = "Classic Ryugay"; - } - - ApplicationIcon selectedIcon = AvailableApplicationIcons.FirstOrDefault(x => x.Name == newIconName); - if (selectedIcon == null) - { - // Fallback to default icon if the selected one is not found - UpdateAppIcon("Classic Ryugay"); - } - - Stream activeIconStream = EmbeddedResources.GetStream(selectedIcon.FullPath); - if (activeIconStream != null) - { - MainWindow.Icon = new Bitmap(activeIconStream); - } - } - - private void WindowIconChanged_Event(object _, ReactiveEventArgs rArgs) => UpdateAppIcon(rArgs.NewValue); } } diff --git a/src/Ryujinx/UI/Windows/StyleableWindow.cs b/src/Ryujinx/UI/Windows/StyleableWindow.cs index 066440382..a91b7593c 100644 --- a/src/Ryujinx/UI/Windows/StyleableWindow.cs +++ b/src/Ryujinx/UI/Windows/StyleableWindow.cs @@ -3,11 +3,13 @@ using Avalonia.Controls; using Avalonia.Controls.Primitives; using Avalonia.Input; using Avalonia.Media; +using Avalonia.Media.Imaging; using Avalonia.Platform; using FluentAvalonia.UI.Windowing; using Ryujinx.Ava.Common.Locale; using Ryujinx.Ava.Systems.Configuration; using Ryujinx.Ava.UI.Controls; +using Ryujinx.Common; using System.Threading.Tasks; namespace Ryujinx.Ava.UI.Windows @@ -39,7 +41,8 @@ namespace Ryujinx.Ava.UI.Windows TitleBar.Height = titleBarHeight.Value; } - Icon = RyujinxLogo.Bitmap; + Icon = RyujinxLogo.CurrentLogoBitmap.Value; + RyujinxLogo.CurrentLogoBitmap.Event += WindowIconChanged_Event; } private void LocaleChanged() @@ -53,6 +56,12 @@ namespace Ryujinx.Ava.UI.Windows ExtendClientAreaChromeHints = ExtendClientAreaChromeHints.SystemChrome | ExtendClientAreaChromeHints.OSXThickTitleBar; } + + private void WindowIconChanged_Event(object _, ReactiveEventArgs rArgs) => UpdateIcon(rArgs.NewValue); + private void UpdateIcon(Bitmap newIcon) + { + Icon = newIcon; + } } public abstract class StyleableWindow : Window @@ -73,7 +82,8 @@ namespace Ryujinx.Ava.UI.Windows LocaleManager.Instance.LocaleChanged += LocaleChanged; LocaleChanged(); - Icon = new WindowIcon(RyujinxLogo.Bitmap); + Icon = new WindowIcon(RyujinxLogo.CurrentLogoBitmap.Value); + RyujinxLogo.CurrentLogoBitmap.Event += WindowIconChanged_Event; } private void LocaleChanged() @@ -87,5 +97,11 @@ namespace Ryujinx.Ava.UI.Windows ExtendClientAreaChromeHints = ExtendClientAreaChromeHints.SystemChrome | ExtendClientAreaChromeHints.OSXThickTitleBar; } + + private void WindowIconChanged_Event(object _, ReactiveEventArgs rArgs) => UpdateIcon(rArgs.NewValue); + private void UpdateIcon(Bitmap newIcon) + { + Icon = new WindowIcon(newIcon); + } } }