diff --git a/Flow.Launcher.Core/Resource/Theme.cs b/Flow.Launcher.Core/Resource/Theme.cs index 64ffec907d9..a46932c6af4 100644 --- a/Flow.Launcher.Core/Resource/Theme.cs +++ b/Flow.Launcher.Core/Resource/Theme.cs @@ -325,7 +325,7 @@ private ResourceDictionary GetResourceDictionary(string theme) return dict; } - private ResourceDictionary GetCurrentResourceDictionary() + public ResourceDictionary GetCurrentResourceDictionary() { return GetResourceDictionary(_settings.Theme); } @@ -772,22 +772,18 @@ private void ApplyPreviewBackground(Color? bgColor = null) { if (bgColor == null) return; - // Copy the existing WindowBorderStyle + // Create a new Style for the preview var previewStyle = new Style(typeof(Border)); - if (Application.Current.Resources.Contains("WindowBorderStyle")) + + // Get the original WindowBorderStyle + if (Application.Current.Resources.Contains("WindowBorderStyle") && + Application.Current.Resources["WindowBorderStyle"] is Style originalStyle) { - if (Application.Current.Resources["WindowBorderStyle"] is Style originalStyle) - { - foreach (var setter in originalStyle.Setters.OfType()) - { - previewStyle.Setters.Add(new Setter(setter.Property, setter.Value)); - } - } + // Copy the original style, including the base style if it exists + CopyStyle(originalStyle, previewStyle); } // Apply background color (remove transparency in color) - // WPF does not allow the use of an acrylic brush within the window's internal area, - // so transparency effects are not applied to the preview. Color backgroundColor = Color.FromRgb(bgColor.Value.R, bgColor.Value.G, bgColor.Value.B); previewStyle.Setters.Add(new Setter(Border.BackgroundProperty, new SolidColorBrush(backgroundColor))); @@ -798,9 +794,26 @@ private void ApplyPreviewBackground(Color? bgColor = null) previewStyle.Setters.Add(new Setter(Border.CornerRadiusProperty, new CornerRadius(5))); previewStyle.Setters.Add(new Setter(Border.BorderThicknessProperty, new Thickness(1))); } + + // Set the new style to the resource Application.Current.Resources["PreviewWindowBorderStyle"] = previewStyle; } + private void CopyStyle(Style originalStyle, Style targetStyle) + { + // If the style is based on another style, copy the base style first + if (originalStyle.BasedOn != null) + { + CopyStyle(originalStyle.BasedOn, targetStyle); + } + + // Copy the setters from the original style + foreach (var setter in originalStyle.Setters.OfType()) + { + targetStyle.Setters.Add(new Setter(setter.Property, setter.Value)); + } + } + private void ColorizeWindow(string theme, BackdropTypes backdropType) { var dict = GetThemeResourceDictionary(theme); diff --git a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs index 7c2457a72c7..8500e7aa444 100644 --- a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs +++ b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs @@ -1,6 +1,5 @@ using System.Collections.Generic; using System.Collections.ObjectModel; -using System.Drawing; using System.Text.Json.Serialization; using System.Windows; using CommunityToolkit.Mvvm.DependencyInjection; @@ -32,8 +31,7 @@ public void Save() { _storage.Save(); } - - private string language = Constant.SystemLanguageCode; + private string _theme = Constant.DefaultTheme; public string Hotkey { get; set; } = $"{KeyConstant.Alt} + {KeyConstant.Space}"; public string OpenResultModifiers { get; set; } = KeyConstant.Alt; @@ -54,12 +52,13 @@ public void Save() public string CycleHistoryUpHotkey { get; set; } = $"{KeyConstant.Alt} + Up"; public string CycleHistoryDownHotkey { get; set; } = $"{KeyConstant.Alt} + Down"; + private string _language = Constant.SystemLanguageCode; public string Language { - get => language; + get => _language; set { - language = value; + _language = value; OnPropertyChanged(); } } @@ -82,18 +81,18 @@ public string Theme /* Appearance Settings. It should be separated from the setting later.*/ public double WindowHeightSize { get; set; } = 42; public double ItemHeightSize { get; set; } = 58; - public double QueryBoxFontSize { get; set; } = 20; + public double QueryBoxFontSize { get; set; } = 16; public double ResultItemFontSize { get; set; } = 16; public double ResultSubItemFontSize { get; set; } = 13; - public string QueryBoxFont { get; set; } = FontFamily.GenericSansSerif.Name; + public string QueryBoxFont { get; set; } = Win32Helper.GetSystemDefaultFont(); public string QueryBoxFontStyle { get; set; } public string QueryBoxFontWeight { get; set; } public string QueryBoxFontStretch { get; set; } - public string ResultFont { get; set; } = FontFamily.GenericSansSerif.Name; + public string ResultFont { get; set; } = Win32Helper.GetSystemDefaultFont(); public string ResultFontStyle { get; set; } public string ResultFontWeight { get; set; } public string ResultFontStretch { get; set; } - public string ResultSubFont { get; set; } = FontFamily.GenericSansSerif.Name; + public string ResultSubFont { get; set; } = Win32Helper.GetSystemDefaultFont(); public string ResultSubFontStyle { get; set; } public string ResultSubFontWeight { get; set; } public string ResultSubFontStretch { get; set; } @@ -116,7 +115,7 @@ public string Theme public double? SettingWindowLeft { get; set; } = null; public WindowState SettingWindowState { get; set; } = WindowState.Normal; - bool _showPlaceholder { get; set; } = false; + private bool _showPlaceholder { get; set; } = true; public bool ShowPlaceholder { get => _showPlaceholder; @@ -129,7 +128,7 @@ public bool ShowPlaceholder } } } - string _placeholderText { get; set; } = string.Empty; + private string _placeholderText { get; set; } = string.Empty; public string PlaceholderText { get => _placeholderText; @@ -142,7 +141,6 @@ public string PlaceholderText } } } - public int CustomExplorerIndex { get; set; } = 0; [JsonIgnore] @@ -309,7 +307,7 @@ public bool KeepMaxResults public bool StartFlowLauncherOnSystemStartup { get; set; } = false; public bool UseLogonTaskForStartup { get; set; } = false; public bool HideOnStartup { get; set; } = true; - bool _hideNotifyIcon { get; set; } + private bool _hideNotifyIcon; public bool HideNotifyIcon { get => _hideNotifyIcon; diff --git a/Flow.Launcher.Infrastructure/Win32Helper.cs b/Flow.Launcher.Infrastructure/Win32Helper.cs index 798501ae3fd..6a5af41df28 100644 --- a/Flow.Launcher.Infrastructure/Win32Helper.cs +++ b/Flow.Launcher.Infrastructure/Win32Helper.cs @@ -1,10 +1,13 @@ using System; +using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.Globalization; +using System.Linq; using System.Runtime.InteropServices; using System.Windows; using System.Windows.Interop; +using System.Windows.Markup; using System.Windows.Media; using Flow.Launcher.Infrastructure.UserSettings; using Microsoft.Win32; @@ -14,6 +17,7 @@ using Windows.Win32.UI.Input.KeyboardAndMouse; using Windows.Win32.UI.WindowsAndMessaging; using Point = System.Windows.Point; +using SystemFonts = System.Windows.SystemFonts; namespace Flow.Launcher.Infrastructure { @@ -595,5 +599,73 @@ public static void OpenImeSettings() } #endregion + + #region System Font + + private static readonly Dictionary _languageToNotoSans = new() + { + { "ko", "Noto Sans KR" }, + { "ja", "Noto Sans JP" }, + { "zh-CN", "Noto Sans SC" }, + { "zh-SG", "Noto Sans SC" }, + { "zh-Hans", "Noto Sans SC" }, + { "zh-TW", "Noto Sans TC" }, + { "zh-HK", "Noto Sans TC" }, + { "zh-MO", "Noto Sans TC" }, + { "zh-Hant", "Noto Sans TC" }, + { "th", "Noto Sans Thai" }, + { "ar", "Noto Sans Arabic" }, + { "he", "Noto Sans Hebrew" }, + { "hi", "Noto Sans Devanagari" }, + { "bn", "Noto Sans Bengali" }, + { "ta", "Noto Sans Tamil" }, + { "el", "Noto Sans Greek" }, + { "ru", "Noto Sans" }, + { "en", "Noto Sans" }, + { "fr", "Noto Sans" }, + { "de", "Noto Sans" }, + { "es", "Noto Sans" }, + { "pt", "Noto Sans" } + }; + + public static string GetSystemDefaultFont() + { + try + { + var culture = CultureInfo.CurrentCulture; + var language = culture.Name; // e.g., "zh-TW" + var langPrefix = language.Split('-')[0]; // e.g., "zh" + + // First, try to find by full name, and if not found, fallback to prefix + if (TryGetNotoFont(language, out var notoFont) || TryGetNotoFont(langPrefix, out notoFont)) + { + // If the font is installed, return it + if (Fonts.SystemFontFamilies.Any(f => f.Source.Equals(notoFont))) + { + return notoFont; + } + } + + // If Noto font is not found, fallback to the system default font + var font = SystemFonts.MessageFontFamily; + if (font.FamilyNames.TryGetValue(XmlLanguage.GetLanguage("en-US"), out var englishName)) + { + return englishName; + } + + return font.Source ?? "Segoe UI"; + } + catch + { + return "Segoe UI"; + } + } + + private static bool TryGetNotoFont(string langKey, out string notoFont) + { + return _languageToNotoSans.TryGetValue(langKey, out notoFont); + } + + #endregion } } diff --git a/Flow.Launcher/Languages/en.xaml b/Flow.Launcher/Languages/en.xaml index 9a9b8e1316e..5a6fd3d74bf 100644 --- a/Flow.Launcher/Languages/en.xaml +++ b/Flow.Launcher/Languages/en.xaml @@ -199,6 +199,9 @@ Result Title Font Result Subtitle Font Reset + Reset to the recommended font and size settings. + Import Theme Size + If a size value intended by the theme designer is available, it will be retrieved and applied. Customize Window Mode Opacity @@ -226,6 +229,7 @@ Clock Date Backdrop Type + The backdrop effect is not applied in the preview. Backdrop supported starting from Windows 11 build 22000 and above None Acrylic diff --git a/Flow.Launcher/Resources/CustomControlTemplate.xaml b/Flow.Launcher/Resources/CustomControlTemplate.xaml index 1ff6ca49c17..ef85e8724b7 100644 --- a/Flow.Launcher/Resources/CustomControlTemplate.xaml +++ b/Flow.Launcher/Resources/CustomControlTemplate.xaml @@ -755,17 +755,33 @@ - + + + + + + + + @@ -773,7 +789,7 @@ - + @@ -792,7 +808,8 @@ - + + @@ -802,7 +819,8 @@ - + + @@ -822,7 +840,7 @@ - + @@ -1103,7 +1121,8 @@ IsOpen="{Binding IsDropDownOpen, RelativeSource={RelativeSource TemplatedParent}}" Placement="Bottom" PlacementTarget="{Binding ElementName=Background}" - PopupAnimation="None"> + PopupAnimation="None" + VerticalOffset="-1"> @@ -1123,11 +1142,11 @@ + Background="{DynamicResource CustomPopUpBorderBG}" + CornerRadius="5"> @@ -1157,8 +1176,8 @@ - - + + diff --git a/Flow.Launcher/Resources/Dark.xaml b/Flow.Launcher/Resources/Dark.xaml index 594a92fbe11..1ec01f8d143 100644 --- a/Flow.Launcher/Resources/Dark.xaml +++ b/Flow.Launcher/Resources/Dark.xaml @@ -13,13 +13,14 @@ - + #198F8F8F + @@ -159,8 +160,14 @@ + + + + + + diff --git a/Flow.Launcher/Resources/Light.xaml b/Flow.Launcher/Resources/Light.xaml index aaa23c8e2d5..4d765d161fe 100644 --- a/Flow.Launcher/Resources/Light.xaml +++ b/Flow.Launcher/Resources/Light.xaml @@ -13,14 +13,16 @@ - + - #0C000000 + #7EFFFFFF - + + + @@ -153,8 +155,17 @@ + + + + + + @@ -165,7 +176,7 @@ 1,1,1,0 0,0,0,2 - 1,1,1,1 + 1,1,1,0 1,1,1,1 diff --git a/Flow.Launcher/ResultListBox.xaml b/Flow.Launcher/ResultListBox.xaml index 4141d9e2f1b..8cb15400f18 100644 --- a/Flow.Launcher/ResultListBox.xaml +++ b/Flow.Launcher/ResultListBox.xaml @@ -180,8 +180,6 @@ !Win32Helper.IsBackdropSupported() ? App.API.GetTranslation("BackdropTypeDisabledToolTip") : ""; public Settings Settings { get; } private readonly Theme _theme = Ioc.Default.GetRequiredService(); @@ -494,7 +495,7 @@ public void Reset() { SelectedQueryBoxFont = new FontFamily(DefaultFont); SelectedQueryBoxFontFaces = new FamilyTypeface { Stretch = FontStretches.Normal, Weight = FontWeights.Normal, Style = FontStyles.Normal }; - QueryBoxFontSize = 20; + QueryBoxFontSize = 16; SelectedResultFont = new FontFamily(DefaultFont); SelectedResultFontFaces = new FamilyTypeface { Stretch = FontStretches.Normal, Weight = FontWeights.Normal, Style = FontStyles.Normal }; @@ -507,4 +508,56 @@ public void Reset() WindowHeightSize = 42; ItemHeightSize = 58; } + + [RelayCommand] + private void Import() + { + var resourceDictionary = _theme.GetCurrentResourceDictionary(); + + if (resourceDictionary["QueryBoxStyle"] is Style queryBoxStyle) + { + var fontSizeSetter = queryBoxStyle.Setters + .OfType() + .FirstOrDefault(setter => setter.Property == TextBox.FontSizeProperty); + if (fontSizeSetter?.Value is double fontSize) + { + QueryBoxFontSize = fontSize; + } + + var heightSetter = queryBoxStyle.Setters + .OfType() + .FirstOrDefault(setter => setter.Property == FrameworkElement.HeightProperty); + if (heightSetter?.Value is double height) + { + WindowHeightSize = height; + } + } + + if (resourceDictionary["ResultItemHeight"] is double resultItemHeight) + { + ItemHeightSize = resultItemHeight; + } + + if (resourceDictionary["ItemTitleStyle"] is Style itemTitleStyle) + { + var fontSizeSetter = itemTitleStyle.Setters + .OfType() + .FirstOrDefault(setter => setter.Property == TextBlock.FontSizeProperty); + if (fontSizeSetter?.Value is double fontSize) + { + ResultItemFontSize = fontSize; + } + } + + if (resourceDictionary["ItemSubTitleStyle"] is Style itemSubTitleStyle) + { + var fontSizeSetter = itemSubTitleStyle.Setters + .OfType() + .FirstOrDefault(setter => setter.Property == TextBlock.FontSizeProperty); + if (fontSizeSetter?.Value is double fontSize) + { + ResultSubItemFontSize = fontSize; + } + } + } } diff --git a/Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml b/Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml index 4782d356ef3..d45d28d8bba 100644 --- a/Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml +++ b/Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml @@ -194,6 +194,7 @@