1111using Bloxstrap . UI . Elements . Editor ;
1212using Bloxstrap . UI . Elements . Dialogs ;
1313using ICSharpCode . SharpZipLib . Zip ;
14+ using System . Windows . Media ;
1415
1516namespace Bloxstrap . UI . ViewModels . Settings
1617{
@@ -26,6 +27,7 @@ public class AppearanceViewModel : NotifyPropertyChangedViewModel
2627 public ICommand RenameCustomThemeCommand => new RelayCommand ( RenameCustomTheme ) ;
2728 public ICommand EditCustomThemeCommand => new RelayCommand ( EditCustomTheme ) ;
2829 public ICommand ExportCustomThemeCommand => new RelayCommand ( ExportCustomTheme ) ;
30+ public ICommand ManageCustomFontCommand => new RelayCommand < string > ( ManageCustomFont ! ) ;
2931
3032 private void PreviewBootstrapper ( )
3133 {
@@ -40,6 +42,113 @@ private void PreviewBootstrapper()
4042 dialog . ShowBootstrapper ( ) ;
4143 }
4244
45+ private bool _isCustomFontApplied ;
46+
47+ public Visibility ChooseCustomFontVisibility =>
48+ _isCustomFontApplied ? Visibility . Collapsed : Visibility . Visible ;
49+
50+ public Visibility DeleteCustomFontVisibility =>
51+ _isCustomFontApplied ? Visibility . Visible : Visibility . Collapsed ;
52+
53+ private void UpdateFontVisibility ( )
54+ {
55+ OnPropertyChanged ( nameof ( ChooseCustomFontVisibility ) ) ;
56+ OnPropertyChanged ( nameof ( DeleteCustomFontVisibility ) ) ;
57+ }
58+
59+ private void ManageCustomFont ( string action )
60+ {
61+ if ( action == "Choose" )
62+ {
63+ var dialog = new OpenFileDialog
64+ {
65+ Filter = "Font files (*.ttf;*.otf)|*.ttf;*.otf|All files (*.*)|*.*"
66+ } ;
67+
68+ if ( dialog . ShowDialog ( ) == true )
69+ {
70+ string fontPath = dialog . FileName ;
71+
72+ try
73+ {
74+ var fontFamily = LoadFontFromFile ( fontPath ) ;
75+ if ( fontFamily != null )
76+ {
77+ ApplyFontGlobally ( fontFamily ) ;
78+ _isCustomFontApplied = true ;
79+ App . Settings . Prop . CustomFontPath = fontPath ;
80+ App . Settings . Save ( ) ;
81+ UpdateFontVisibility ( ) ;
82+ }
83+ }
84+ catch ( Exception ex )
85+ {
86+ MessageBox . Show ( $ "Failed to load font: { ex . Message } ", "Font Error" , MessageBoxButton . OK , MessageBoxImage . Error ) ;
87+ }
88+ }
89+ }
90+ else if ( action == "Remove" )
91+ {
92+ var defaultFont = new System . Windows . Media . FontFamily ( "Segoe UI" ) ;
93+ ApplyFontGlobally ( defaultFont ) ;
94+ _isCustomFontApplied = false ;
95+ App . Settings . Prop . CustomFontPath = null ;
96+ App . Settings . Save ( ) ;
97+ UpdateFontVisibility ( ) ;
98+ }
99+ }
100+
101+ private System . Windows . Media . FontFamily ? LoadFontFromFile ( string fontFilePath )
102+ {
103+ if ( ! File . Exists ( fontFilePath ) )
104+ return null ;
105+
106+ string tempFontsFolder = Path . Combine ( Path . GetTempPath ( ) , "BloxstrapFonts" ) ;
107+ Directory . CreateDirectory ( tempFontsFolder ) ;
108+
109+ string destFontPath = Path . Combine ( tempFontsFolder , Path . GetFileName ( fontFilePath ) ) ;
110+ File . Copy ( fontFilePath , destFontPath , overwrite : true ) ;
111+
112+ var fontDirectoryUri = new Uri ( Path . GetDirectoryName ( destFontPath ) + Path . DirectorySeparatorChar ) ;
113+ var fontFamilies = Fonts . GetFontFamilies ( fontDirectoryUri ) ;
114+
115+ return fontFamilies . FirstOrDefault ( ) ;
116+ }
117+
118+ private void ApplyFontGlobally ( System . Windows . Media . FontFamily fontFamily )
119+ {
120+ Application . Current . Resources [ SystemFonts . MessageFontFamilyKey ] = fontFamily ;
121+
122+ foreach ( Window window in Application . Current . Windows )
123+ {
124+ window . FontFamily = fontFamily ;
125+ }
126+ }
127+
128+ private void ApplySavedCustomFont ( )
129+ {
130+ string ? savedFontPath = App . Settings . Prop . CustomFontPath ;
131+
132+ if ( ! string . IsNullOrWhiteSpace ( savedFontPath ) && File . Exists ( savedFontPath ) )
133+ {
134+ try
135+ {
136+ var font = LoadFontFromFile ( savedFontPath ) ;
137+ if ( font != null )
138+ {
139+ ApplyFontGlobally ( font ) ;
140+ _isCustomFontApplied = true ;
141+ }
142+ }
143+ catch ( Exception ex )
144+ {
145+ App . Logger . WriteLine ( "AppearanceViewModel" , $ "Failed to load saved font: { ex } ") ;
146+ }
147+ }
148+
149+ UpdateFontVisibility ( ) ;
150+ }
151+
43152 private void BrowseCustomIconLocation ( )
44153 {
45154 var dialog = new OpenFileDialog
@@ -65,6 +174,7 @@ public AppearanceViewModel(Page page)
65174 ThemeIcons . Add ( new ThemeEntry { IconType = ( Theme ) entry } ) ;
66175
67176 PopulateCustomThemes ( ) ;
177+ ApplySavedCustomFont ( ) ;
68178 }
69179
70180 public IEnumerable < Theme > Themes { get ; } = Enum . GetValues ( typeof ( Theme ) ) . Cast < Theme > ( ) ;
0 commit comments