6
6
using System . Threading . Tasks ;
7
7
using System . Windows ;
8
8
using System . Windows . Controls ;
9
+ using System . Windows . Controls . Primitives ;
9
10
using System . Windows . Markup ;
10
11
using System . Windows . Media ;
11
12
using System . Windows . Media . Effects ;
16
17
using Flow . Launcher . Infrastructure . UserSettings ;
17
18
using Flow . Launcher . Plugin ;
18
19
using Microsoft . Win32 ;
19
- using TextBox = System . Windows . Controls . TextBox ;
20
20
21
21
namespace Flow . Launcher . Core . Resource
22
22
{
@@ -56,20 +56,23 @@ public Theme(IPublicAPI publicAPI, Settings settings)
56
56
MakeSureThemeDirectoriesExist ( ) ;
57
57
58
58
var dicts = Application . Current . Resources . MergedDictionaries ;
59
- _oldResource = dicts . First ( d =>
59
+ _oldResource = dicts . FirstOrDefault ( d =>
60
60
{
61
- if ( d . Source == null )
62
- return false ;
61
+ if ( d . Source == null ) return false ;
63
62
64
63
var p = d . Source . AbsolutePath ;
65
- var dir = Path . GetDirectoryName ( p ) . NonNull ( ) ;
66
- var info = new DirectoryInfo ( dir ) ;
67
- var f = info . Name ;
68
- var e = Path . GetExtension ( p ) ;
69
- var found = f == Folder && e == Extension ;
70
- return found ;
64
+ return p . Contains ( Folder ) && Path . GetExtension ( p ) == Extension ;
71
65
} ) ;
72
- _oldTheme = Path . GetFileNameWithoutExtension ( _oldResource . Source . AbsolutePath ) ;
66
+
67
+ if ( _oldResource != null )
68
+ {
69
+ _oldTheme = Path . GetFileNameWithoutExtension ( _oldResource . Source . AbsolutePath ) ;
70
+ }
71
+ else
72
+ {
73
+ Log . Error ( "Current theme resource not found. Initializing with default theme." ) ;
74
+ _oldTheme = Constant . DefaultTheme ;
75
+ } ;
73
76
}
74
77
75
78
#endregion
@@ -98,13 +101,152 @@ private void MakeSureThemeDirectoriesExist()
98
101
99
102
private void UpdateResourceDictionary ( ResourceDictionary dictionaryToUpdate )
100
103
{
101
- var dicts = Application . Current . Resources . MergedDictionaries ;
104
+ // Add new resources
105
+ if ( ! Application . Current . Resources . MergedDictionaries . Contains ( dictionaryToUpdate ) )
106
+ {
107
+ Application . Current . Resources . MergedDictionaries . Add ( dictionaryToUpdate ) ;
108
+ }
109
+
110
+ // Remove old resources
111
+ if ( _oldResource != null && _oldResource != dictionaryToUpdate &&
112
+ Application . Current . Resources . MergedDictionaries . Contains ( _oldResource ) )
113
+ {
114
+ Application . Current . Resources . MergedDictionaries . Remove ( _oldResource ) ;
115
+ }
102
116
103
- dicts . Remove ( _oldResource ) ;
104
- dicts . Add ( dictionaryToUpdate ) ;
105
117
_oldResource = dictionaryToUpdate ;
106
118
}
107
119
120
+ /// <summary>
121
+ /// Updates only the font settings and refreshes the UI.
122
+ /// </summary>
123
+ public void UpdateFonts ( )
124
+ {
125
+ try
126
+ {
127
+ // Load a ResourceDictionary for the specified theme.
128
+ var themeName = GetCurrentTheme ( ) ;
129
+ var dict = GetThemeResourceDictionary ( themeName ) ;
130
+
131
+ // Apply font settings to the theme resource.
132
+ ApplyFontSettings ( dict ) ;
133
+ UpdateResourceDictionary ( dict ) ;
134
+
135
+ // Must apply blur and drop shadow effects
136
+ _ = RefreshFrameAsync ( ) ;
137
+ }
138
+ catch ( Exception e )
139
+ {
140
+ Log . Exception ( "Error occurred while updating theme fonts" , e ) ;
141
+ }
142
+ }
143
+
144
+ /// <summary>
145
+ /// Loads and applies font settings to the theme resource.
146
+ /// </summary>
147
+ private void ApplyFontSettings ( ResourceDictionary dict )
148
+ {
149
+ if ( dict [ "QueryBoxStyle" ] is Style queryBoxStyle &&
150
+ dict [ "QuerySuggestionBoxStyle" ] is Style querySuggestionBoxStyle )
151
+ {
152
+ var fontFamily = new FontFamily ( _settings . QueryBoxFont ) ;
153
+ var fontStyle = FontHelper . GetFontStyleFromInvariantStringOrNormal ( _settings . QueryBoxFontStyle ) ;
154
+ var fontWeight = FontHelper . GetFontWeightFromInvariantStringOrNormal ( _settings . QueryBoxFontWeight ) ;
155
+ var fontStretch = FontHelper . GetFontStretchFromInvariantStringOrNormal ( _settings . QueryBoxFontStretch ) ;
156
+
157
+ SetFontProperties ( queryBoxStyle , fontFamily , fontStyle , fontWeight , fontStretch , true ) ;
158
+ SetFontProperties ( querySuggestionBoxStyle , fontFamily , fontStyle , fontWeight , fontStretch , false ) ;
159
+ }
160
+
161
+ if ( dict [ "ItemTitleStyle" ] is Style resultItemStyle &&
162
+ dict [ "ItemTitleSelectedStyle" ] is Style resultItemSelectedStyle &&
163
+ dict [ "ItemHotkeyStyle" ] is Style resultHotkeyItemStyle &&
164
+ dict [ "ItemHotkeySelectedStyle" ] is Style resultHotkeyItemSelectedStyle )
165
+ {
166
+ var fontFamily = new FontFamily ( _settings . ResultFont ) ;
167
+ var fontStyle = FontHelper . GetFontStyleFromInvariantStringOrNormal ( _settings . ResultFontStyle ) ;
168
+ var fontWeight = FontHelper . GetFontWeightFromInvariantStringOrNormal ( _settings . ResultFontWeight ) ;
169
+ var fontStretch = FontHelper . GetFontStretchFromInvariantStringOrNormal ( _settings . ResultFontStretch ) ;
170
+
171
+ SetFontProperties ( resultItemStyle , fontFamily , fontStyle , fontWeight , fontStretch , false ) ;
172
+ SetFontProperties ( resultItemSelectedStyle , fontFamily , fontStyle , fontWeight , fontStretch , false ) ;
173
+ SetFontProperties ( resultHotkeyItemStyle , fontFamily , fontStyle , fontWeight , fontStretch , false ) ;
174
+ SetFontProperties ( resultHotkeyItemSelectedStyle , fontFamily , fontStyle , fontWeight , fontStretch , false ) ;
175
+ }
176
+
177
+ if ( dict [ "ItemSubTitleStyle" ] is Style resultSubItemStyle &&
178
+ dict [ "ItemSubTitleSelectedStyle" ] is Style resultSubItemSelectedStyle )
179
+ {
180
+ var fontFamily = new FontFamily ( _settings . ResultSubFont ) ;
181
+ var fontStyle = FontHelper . GetFontStyleFromInvariantStringOrNormal ( _settings . ResultSubFontStyle ) ;
182
+ var fontWeight = FontHelper . GetFontWeightFromInvariantStringOrNormal ( _settings . ResultSubFontWeight ) ;
183
+ var fontStretch = FontHelper . GetFontStretchFromInvariantStringOrNormal ( _settings . ResultSubFontStretch ) ;
184
+
185
+ SetFontProperties ( resultSubItemStyle , fontFamily , fontStyle , fontWeight , fontStretch , false ) ;
186
+ SetFontProperties ( resultSubItemSelectedStyle , fontFamily , fontStyle , fontWeight , fontStretch , false ) ;
187
+ }
188
+ }
189
+
190
+ /// <summary>
191
+ /// Applies font properties to a Style.
192
+ /// </summary>
193
+ private static void SetFontProperties ( Style style , FontFamily fontFamily , FontStyle fontStyle , FontWeight fontWeight , FontStretch fontStretch , bool isTextBox )
194
+ {
195
+ // Remove existing font-related setters
196
+ if ( isTextBox )
197
+ {
198
+ // First, find the setters to remove and store them in a list
199
+ var settersToRemove = style . Setters
200
+ . OfType < Setter > ( )
201
+ . Where ( setter =>
202
+ setter . Property == Control . FontFamilyProperty ||
203
+ setter . Property == Control . FontStyleProperty ||
204
+ setter . Property == Control . FontWeightProperty ||
205
+ setter . Property == Control . FontStretchProperty )
206
+ . ToList ( ) ;
207
+
208
+ // Remove each found setter one by one
209
+ foreach ( var setter in settersToRemove )
210
+ {
211
+ style . Setters . Remove ( setter ) ;
212
+ }
213
+
214
+ // Add New font setter
215
+ style . Setters . Add ( new Setter ( Control . FontFamilyProperty , fontFamily ) ) ;
216
+ style . Setters . Add ( new Setter ( Control . FontStyleProperty , fontStyle ) ) ;
217
+ style . Setters . Add ( new Setter ( Control . FontWeightProperty , fontWeight ) ) ;
218
+ style . Setters . Add ( new Setter ( Control . FontStretchProperty , fontStretch ) ) ;
219
+
220
+ // Set caret brush (retain existing logic)
221
+ var caretBrushPropertyValue = style . Setters . OfType < Setter > ( ) . Any ( x => x . Property . Name == "CaretBrush" ) ;
222
+ var foregroundPropertyValue = style . Setters . OfType < Setter > ( ) . Where ( x => x . Property . Name == "Foreground" )
223
+ . Select ( x => x . Value ) . FirstOrDefault ( ) ;
224
+ if ( ! caretBrushPropertyValue && foregroundPropertyValue != null )
225
+ style . Setters . Add ( new Setter ( TextBoxBase . CaretBrushProperty , foregroundPropertyValue ) ) ;
226
+ }
227
+ else
228
+ {
229
+ var settersToRemove = style . Setters
230
+ . OfType < Setter > ( )
231
+ . Where ( setter =>
232
+ setter . Property == TextBlock . FontFamilyProperty ||
233
+ setter . Property == TextBlock . FontStyleProperty ||
234
+ setter . Property == TextBlock . FontWeightProperty ||
235
+ setter . Property == TextBlock . FontStretchProperty )
236
+ . ToList ( ) ;
237
+
238
+ foreach ( var setter in settersToRemove )
239
+ {
240
+ style . Setters . Remove ( setter ) ;
241
+ }
242
+
243
+ style . Setters . Add ( new Setter ( TextBlock . FontFamilyProperty , fontFamily ) ) ;
244
+ style . Setters . Add ( new Setter ( TextBlock . FontStyleProperty , fontStyle ) ) ;
245
+ style . Setters . Add ( new Setter ( TextBlock . FontWeightProperty , fontWeight ) ) ;
246
+ style . Setters . Add ( new Setter ( TextBlock . FontStretchProperty , fontStretch ) ) ;
247
+ }
248
+ }
249
+
108
250
private ResourceDictionary GetThemeResourceDictionary ( string theme )
109
251
{
110
252
var uri = GetThemePath ( theme ) ;
@@ -128,22 +270,22 @@ private ResourceDictionary GetResourceDictionary(string theme)
128
270
var fontWeight = FontHelper . GetFontWeightFromInvariantStringOrNormal ( _settings . QueryBoxFontWeight ) ;
129
271
var fontStretch = FontHelper . GetFontStretchFromInvariantStringOrNormal ( _settings . QueryBoxFontStretch ) ;
130
272
131
- queryBoxStyle . Setters . Add ( new Setter ( TextBox . FontFamilyProperty , fontFamily ) ) ;
132
- queryBoxStyle . Setters . Add ( new Setter ( TextBox . FontStyleProperty , fontStyle ) ) ;
133
- queryBoxStyle . Setters . Add ( new Setter ( TextBox . FontWeightProperty , fontWeight ) ) ;
134
- queryBoxStyle . Setters . Add ( new Setter ( TextBox . FontStretchProperty , fontStretch ) ) ;
273
+ queryBoxStyle . Setters . Add ( new Setter ( Control . FontFamilyProperty , fontFamily ) ) ;
274
+ queryBoxStyle . Setters . Add ( new Setter ( Control . FontStyleProperty , fontStyle ) ) ;
275
+ queryBoxStyle . Setters . Add ( new Setter ( Control . FontWeightProperty , fontWeight ) ) ;
276
+ queryBoxStyle . Setters . Add ( new Setter ( Control . FontStretchProperty , fontStretch ) ) ;
135
277
136
278
var caretBrushPropertyValue = queryBoxStyle . Setters . OfType < Setter > ( ) . Any ( x => x . Property . Name == "CaretBrush" ) ;
137
279
var foregroundPropertyValue = queryBoxStyle . Setters . OfType < Setter > ( ) . Where ( x => x . Property . Name == "Foreground" )
138
280
. Select ( x => x . Value ) . FirstOrDefault ( ) ;
139
281
if ( ! caretBrushPropertyValue && foregroundPropertyValue != null ) //otherwise BaseQueryBoxStyle will handle styling
140
- queryBoxStyle . Setters . Add ( new Setter ( TextBox . CaretBrushProperty , foregroundPropertyValue ) ) ;
282
+ queryBoxStyle . Setters . Add ( new Setter ( TextBoxBase . CaretBrushProperty , foregroundPropertyValue ) ) ;
141
283
142
284
// Query suggestion box's font style is aligned with query box
143
- querySuggestionBoxStyle . Setters . Add ( new Setter ( TextBox . FontFamilyProperty , fontFamily ) ) ;
144
- querySuggestionBoxStyle . Setters . Add ( new Setter ( TextBox . FontStyleProperty , fontStyle ) ) ;
145
- querySuggestionBoxStyle . Setters . Add ( new Setter ( TextBox . FontWeightProperty , fontWeight ) ) ;
146
- querySuggestionBoxStyle . Setters . Add ( new Setter ( TextBox . FontStretchProperty , fontStretch ) ) ;
285
+ querySuggestionBoxStyle . Setters . Add ( new Setter ( Control . FontFamilyProperty , fontFamily ) ) ;
286
+ querySuggestionBoxStyle . Setters . Add ( new Setter ( Control . FontStyleProperty , fontStyle ) ) ;
287
+ querySuggestionBoxStyle . Setters . Add ( new Setter ( Control . FontWeightProperty , fontWeight ) ) ;
288
+ querySuggestionBoxStyle . Setters . Add ( new Setter ( Control . FontStretchProperty , fontStretch ) ) ;
147
289
}
148
290
149
291
if ( dict [ "ItemTitleStyle" ] is Style resultItemStyle &&
@@ -180,7 +322,7 @@ private ResourceDictionary GetResourceDictionary(string theme)
180
322
/* Ignore Theme Window Width and use setting */
181
323
var windowStyle = dict [ "WindowStyle" ] as Style ;
182
324
var width = _settings . WindowSize ;
183
- windowStyle . Setters . Add ( new Setter ( Window . WidthProperty , width ) ) ;
325
+ windowStyle . Setters . Add ( new Setter ( FrameworkElement . WidthProperty , width ) ) ;
184
326
return dict ;
185
327
}
186
328
@@ -265,11 +407,12 @@ public bool ChangeTheme(string theme = null)
265
407
try
266
408
{
267
409
if ( string . IsNullOrEmpty ( path ) )
268
- throw new DirectoryNotFoundException ( "Theme path can't be found <{path}>" ) ;
410
+ throw new DirectoryNotFoundException ( $ "Theme path can't be found <{ path } >") ;
269
411
270
- // reload all resources even if the theme itself hasn't changed in order to pickup changes
271
- // to things like fonts
272
- UpdateResourceDictionary ( GetResourceDictionary ( theme ) ) ;
412
+ // Retrieve theme resource – always use the resource with font settings applied.
413
+ var resourceDict = GetResourceDictionary ( theme ) ;
414
+
415
+ UpdateResourceDictionary ( resourceDict ) ;
273
416
274
417
_settings . Theme = theme ;
275
418
@@ -280,10 +423,11 @@ public bool ChangeTheme(string theme = null)
280
423
}
281
424
282
425
BlurEnabled = IsBlurTheme ( ) ;
283
- //if (_settings.UseDropShadowEffect)
284
- // AddDropShadowEffectToCurrentTheme();
285
- //Win32Helper.SetBlurForWindow(Application.Current.MainWindow, BlurEnabled);
286
- _ = SetBlurForWindowAsync ( ) ;
426
+
427
+ // Can only apply blur but here also apply drop shadow effect to avoid possible drop shadow effect issues
428
+ _ = RefreshFrameAsync ( ) ;
429
+
430
+ return true ;
287
431
}
288
432
catch ( DirectoryNotFoundException )
289
433
{
@@ -305,7 +449,6 @@ public bool ChangeTheme(string theme = null)
305
449
}
306
450
return false ;
307
451
}
308
- return true ;
309
452
}
310
453
311
454
#endregion
@@ -481,17 +624,14 @@ await Application.Current.Dispatcher.InvokeAsync(() =>
481
624
482
625
private void SetBlurForWindow ( string theme , BackdropTypes backdropType )
483
626
{
484
- var dict = GetThemeResourceDictionary ( theme ) ;
485
- if ( dict == null )
486
- return ;
627
+ var dict = GetResourceDictionary ( theme ) ;
628
+ if ( dict == null ) return ;
487
629
488
630
var windowBorderStyle = dict . Contains ( "WindowBorderStyle" ) ? dict [ "WindowBorderStyle" ] as Style : null ;
489
- if ( windowBorderStyle == null )
490
- return ;
631
+ if ( windowBorderStyle == null ) return ;
491
632
492
- Window mainWindow = Application . Current . MainWindow ;
493
- if ( mainWindow == null )
494
- return ;
633
+ var mainWindow = Application . Current . MainWindow ;
634
+ if ( mainWindow == null ) return ;
495
635
496
636
// Check if the theme supports blur
497
637
bool hasBlur = dict . Contains ( "ThemeBlurEnabled" ) && dict [ "ThemeBlurEnabled" ] is bool b && b ;
0 commit comments