2021-08-24 12:17:31 -04:00
// Copyright Epic Games, Inc. All Rights Reserved.
# include "SlateFontDlgWindow.h"
# include "Fonts/CompositeFont.h"
# include "HAL/FileManager.h"
# include "HAL/PlatformFileManager.h"
# include "Widgets/Input/SNumericEntryBox.h"
# include "Widgets/Colors/SColorPicker.h"
# include "Widgets/Colors/SColorBlock.h"
# include <fontconfig.h>
# define LOCTEXT_NAMESPACE "SlateFontDialogNamespace"
DEFINE_LOG_CATEGORY_STATIC ( LogSlateFontDialog , Log , All ) ;
namespace
{
2021-08-26 12:34:18 -04:00
FcPattern * GetFontMatch ( TSharedPtr < FString > SelectedFont , TSharedPtr < FString > SelectedTypeface )
{
FcPattern * Query = FcPatternCreate ( ) ;
FcPatternAddString ( Query , FC_FAMILY , reinterpret_cast < const FcChar8 * > ( TCHAR_TO_UTF8 ( * * SelectedFont ) ) ) ;
FcPatternAddString ( Query , FC_STYLE , reinterpret_cast < const FcChar8 * > ( TCHAR_TO_UTF8 ( * * SelectedTypeface ) ) ) ;
2021-08-24 12:17:31 -04:00
2021-08-26 12:34:18 -04:00
// Increase the scope of possible matches
FcConfigSubstitute ( nullptr , Query , FcMatchPattern ) ;
FcDefaultSubstitute ( Query ) ;
2021-08-24 12:17:31 -04:00
2021-08-26 12:34:18 -04:00
FcResult Result = FcResultNoMatch ;
FcPattern * Match = FcFontMatch ( nullptr , Query , & Result ) ;
if ( Result ! = FcResultMatch )
{
UE_LOG ( LogSlateFontDialog , Warning , TEXT ( " FontConfig failed to match a font, error number: %i " ) , static_cast < int > ( Result ) ) ;
Match = nullptr ;
}
2021-08-24 12:17:31 -04:00
2021-08-26 12:34:18 -04:00
FcPatternDestroy ( Query ) ;
2021-08-24 12:17:31 -04:00
2021-08-26 12:34:18 -04:00
return Match ;
}
2021-08-24 12:17:31 -04:00
2021-08-26 12:34:18 -04:00
FString GetFontFilename ( TSharedPtr < FString > SelectedFont , TSharedPtr < FString > SelectedTypeface )
{
FcPattern * Match = GetFontMatch ( SelectedFont , SelectedTypeface ) ;
2021-08-24 12:17:31 -04:00
2021-08-26 12:34:18 -04:00
FcChar8 * FilenameRaw = nullptr ;
FcResult Result = FcPatternGetString ( Match , FC_FILE , 0 , & FilenameRaw ) ;
if ( Result ! = FcResultMatch )
{
UE_LOG ( LogSlateFontDialog , Warning , TEXT ( " FontConfig failed to match a font, error number: %i " ) , static_cast < int > ( Result ) ) ;
}
FString Filename ( UTF8_TO_TCHAR ( FilenameRaw ) ) ;
2021-08-24 12:17:31 -04:00
2021-08-26 12:34:18 -04:00
FcPatternDestroy ( Match ) ;
2021-08-24 12:17:31 -04:00
2021-08-26 12:34:18 -04:00
return Filename ;
}
2021-08-24 12:17:31 -04:00
}
FSlateFontInfo FSlateFontDlgWindow : : GetSampleFont ( ) const
{
2021-08-26 12:34:18 -04:00
TSharedPtr < FCompositeFont > SampleFont = MakeShareable ( new FCompositeFont ( * * SelectedFont , GetFontFilename ( SelectedFont , SelectedTypeface ) , EFontHinting : : Default , EFontLoadingPolicy : : LazyLoad ) ) ;
return FSlateFontInfo ( SampleFont , SampleTextSize ) ;
2021-08-24 12:17:31 -04:00
}
void FSlateFontDlgWindow : : LoadFonts ( )
{
2021-08-26 12:34:18 -04:00
for ( int i = 0 ; i < FontSet - > nfont ; i + + )
{
FcPattern * Pattern = FontSet - > fonts [ i ] ;
2021-08-24 12:17:31 -04:00
2021-08-26 12:34:18 -04:00
// Grab the font name
FcChar8 * NameRaw = nullptr ;
FcResult Result = FcPatternGetString ( Pattern , FC_FAMILY , 0 , & NameRaw ) ;
if ( Result ! = FcResultMatch )
{
UE_LOG ( LogSlateFontDialog , Warning , TEXT ( " FontConfig failed to load a font, error number: %i " ) , static_cast < int > ( Result ) ) ;
continue ;
}
FString Name ( UTF8_TO_TCHAR ( NameRaw ) ) ;
2021-08-24 12:17:31 -04:00
2021-08-26 12:34:18 -04:00
// Grab the style/typeface name
FcChar8 * StyleRaw = nullptr ;
Result = FcPatternGetString ( Pattern , FC_STYLE , 0 , & StyleRaw ) ;
if ( Result ! = FcResultMatch )
{
UE_LOG ( LogSlateFontDialog , Warning , TEXT ( " FontConfig failed to load a font, error number: %i " ) , static_cast < int > ( Result ) ) ;
continue ;
}
FString Style ( UTF8_TO_TCHAR ( StyleRaw ) ) ;
TArray < TSharedPtr < FString > > & Typefaces = TypefaceList . FindOrAdd ( Name ) ;
if ( ! Typefaces . ContainsByPredicate ( [ & Style ] ( const TSharedPtr < FString > & Element ) { return * Element = = Style ; } ) )
{
Typefaces . Add ( MakeShareable ( new FString ( Style ) ) ) ;
}
}
// Can't use TMap::GenerateKeyArray because we need TSharedPtr<FString>, not FString
for ( const TPair < FString , TArray < TSharedPtr < FString > > > & Typeface : TypefaceList )
{
FontList . AddUnique ( MakeShareable ( new FString ( Typeface . Key ) ) ) ;
}
2021-08-24 12:17:31 -04:00
2021-08-26 12:34:18 -04:00
FontList . Sort ( [ ] ( const TSharedPtr < FString > & First , const TSharedPtr < FString > & Second ) { return * First < * Second ; } ) ;
2021-08-24 12:17:31 -04:00
2021-08-26 12:34:18 -04:00
SelectedFont = FontList [ 0 ] ;
SelectedTypefaceList = * TypefaceList . Find ( * SelectedFont ) ;
SelectedTypeface = SelectedTypefaceList [ 0 ] ;
2021-08-24 12:17:31 -04:00
}
BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION
FReply FSlateFontDlgWindow : : OpenColorPicker ( )
{
2021-08-26 12:34:18 -04:00
TSharedPtr < SWindow > ColorWindow ;
SAssignNew ( ColorWindow , SWindow )
. Title ( LOCTEXT ( " ColorPickerTest-WindowTitle-StandardColor " , " Standard Color " ) )
. ClientSize ( SColorPicker : : DEFAULT_WINDOW_SIZE )
. IsPopupWindow ( true ) ;
2021-08-24 12:17:31 -04:00
2021-08-26 12:34:18 -04:00
TSharedPtr < SBox > ColorPicker = SNew ( SBox )
. Padding ( 10.0f )
[
SNew ( SColorPicker )
. ParentWindow ( ColorWindow )
. UseAlpha ( false )
. OnColorCommitted_Lambda ( [ this ] ( const FLinearColor & NewColor )
{
FontColor = NewColor ;
FontColor . A = 1.0f ;
SampleTextBlock - > SetColorAndOpacity ( FontColor ) ;
} )
] ;
2021-08-24 12:17:31 -04:00
2021-08-26 12:34:18 -04:00
ColorWindow - > SetContent ( ColorPicker . ToSharedRef ( ) ) ;
2021-08-24 12:17:31 -04:00
2021-08-26 12:34:18 -04:00
FSlateApplication : : Get ( ) . AddModalWindow ( ColorWindow . ToSharedRef ( ) , FGlobalTabmanager : : Get ( ) - > GetRootWindow ( ) ) ;
return FReply : : Handled ( ) ;
2021-08-24 12:17:31 -04:00
}
END_SLATE_FUNCTION_BUILD_OPTIMIZATION
FSlateFontDlgWindow : : FSlateFontDlgWindow ( bool & OutSuccess )
{
2021-08-26 12:34:18 -04:00
FontSet = FcConfigGetFonts ( nullptr , FcSetSystem ) ;
if ( FontSet - > nfont < 1 )
{
OutSuccess = false ;
UE_LOG ( LogSlateFontDialog , Warning , TEXT ( " FontConfig could not find any fonts " ) ) ;
return ;
}
OutSuccess = true ;
LoadFonts ( ) ;
2021-08-24 12:17:31 -04:00
2021-08-26 12:34:18 -04:00
SampleTextStyle = FTextBlockStyle ( )
. SetFont ( GetSampleFont ( ) )
. SetColorAndOpacity ( FontColor ) ;
2021-08-24 12:17:31 -04:00
}
BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION
// OutFontName actually gets set to the filepath of the chosen font to reduce dependencies in UTrueTypeFontFactory::LoadFontFace within TTFontImport.cpp
void FSlateFontDlgWindow : : OpenFontWindow ( FString & OutFontName , float & OutHeight , EFontImportFlags & OutFlags , bool & OutSuccess )
{
2021-08-26 12:34:18 -04:00
OutFontName = GetFontFilename ( SelectedFont , SelectedTypeface ) ;
OutHeight = ( float ) FontSize ;
OutFlags = EFontImportFlags : : None ;
EnumAddFlags ( OutFlags , EFontImportFlags : : EnableAntialiasing ) ;
EnumAddFlags ( OutFlags , EFontImportFlags : : AlphaOnly ) ;
2021-08-24 12:17:31 -04:00
2021-08-26 12:34:18 -04:00
// Create the font dialogue window
SAssignNew ( Window , SWindow )
. Title ( FText : : FromString ( TEXT ( " Fonts " ) ) )
. SizingRule ( ESizingRule : : Autosized )
. AutoCenter ( EAutoCenter : : PreferredWorkArea )
. SupportsMaximize ( false )
. SupportsMinimize ( false )
. HasCloseButton ( false )
[
SNew ( SGridPanel )
2021-08-24 12:17:31 -04:00
2021-08-26 12:34:18 -04:00
// Font
+ SGridPanel : : Slot ( 0 , 0 )
. Padding ( 8.0f )
[
SNew ( SVerticalBox )
2021-08-24 12:17:31 -04:00
2021-08-26 12:34:18 -04:00
// Name
+ SVerticalBox : : Slot ( )
. AutoHeight ( )
[
SNew ( STextBlock ) . Text ( FText : : FromString ( TEXT ( " Font " ) ) )
]
2021-08-24 12:17:31 -04:00
2021-08-26 12:34:18 -04:00
// Dropdown
+ SVerticalBox : : Slot ( )
. AutoHeight ( )
[
SNew ( SBox )
. WidthOverride ( 180.0f )
[
SNew ( STextComboBox )
. OptionsSource ( & FontList )
. InitiallySelectedItem ( FontList [ 0 ] )
. OnSelectionChanged_Lambda ( [ this , & OutFontName ] ( TSharedPtr < FString > InSelection , ESelectInfo : : Type InSelectInfo )
{
if ( InSelection . IsValid ( ) )
{
SelectedFont = InSelection ;
SelectedTypefaceList = * TypefaceList . Find ( * SelectedFont ) ;
SelectedTypeface = SelectedTypefaceList [ 0 ] ;
OutFontName = GetFontFilename ( SelectedFont , SelectedTypeface ) ;
TypefaceDropdown - > RefreshOptions ( ) ;
TypefaceDropdown - > SetSelectedItem ( SelectedTypefaceList [ 0 ] ) ;
2021-08-24 12:17:31 -04:00
2021-08-26 12:34:18 -04:00
SampleTextBlock - > SetFont ( GetSampleFont ( ) ) ;
}
} )
]
]
]
2021-08-24 12:17:31 -04:00
2021-08-26 12:34:18 -04:00
// Typeface
+ SGridPanel : : Slot ( 1 , 0 )
. Padding ( 8.0f )
[
SNew ( SVerticalBox )
// Name
+ SVerticalBox : : Slot ( )
. AutoHeight ( )
[
SNew ( STextBlock ) . Text ( FText : : FromString ( TEXT ( " Typeface " ) ) )
]
2021-08-24 12:17:31 -04:00
2021-08-26 12:34:18 -04:00
// Dropdown
+ SVerticalBox : : Slot ( )
. AutoHeight ( )
[
SNew ( SBox )
. WidthOverride ( 100.0f )
[
SAssignNew ( TypefaceDropdown , STextComboBox )
. OptionsSource ( & SelectedTypefaceList )
. InitiallySelectedItem ( SelectedTypefaceList [ 0 ] )
. OnSelectionChanged_Lambda ( [ this ] ( TSharedPtr < FString > InSelection , ESelectInfo : : Type InSelectInfo )
{
if ( InSelection . IsValid ( ) )
{
SelectedTypeface = InSelection ;
SampleTextBlock - > SetFont ( GetSampleFont ( ) ) ;
}
} )
]
]
]
2021-08-24 12:17:31 -04:00
2021-08-26 12:34:18 -04:00
// Size
+ SGridPanel : : Slot ( 2 , 0 )
. Padding ( 8.0f )
[
SNew ( SVerticalBox )
2021-08-24 12:17:31 -04:00
2021-08-26 12:34:18 -04:00
// Name
+ SVerticalBox : : Slot ( )
. AutoHeight ( )
[
SNew ( STextBlock ) . Text ( FText : : FromString ( TEXT ( " Size " ) ) )
]
2021-08-24 12:17:31 -04:00
2021-08-26 12:34:18 -04:00
// Text box
+ SVerticalBox : : Slot ( )
. HAlign ( HAlign_Left )
. AutoHeight ( )
[
SNew ( SNumericEntryBox < uint8 > )
. Value_Lambda ( [ this ] { return FontSize ; } )
. OnValueCommitted_Lambda ( [ this , & OutHeight ] ( float InValue , ETextCommit : : Type CommitInfo )
{
FontSize = InValue ;
OutHeight = static_cast < float > ( FontSize ) ;
} )
]
]
2021-08-24 12:17:31 -04:00
2021-08-26 12:34:18 -04:00
// Effects
+ SGridPanel : : Slot ( 0 , 1 )
. Padding ( 8.0f )
[
SNew ( SVerticalBox )
2021-08-24 12:17:31 -04:00
2021-08-26 12:34:18 -04:00
// Section name
+ SVerticalBox : : Slot ( )
. AutoHeight ( )
[
SNew ( STextBlock )
. Text ( FText : : FromString ( TEXT ( " Effects " ) ) )
]
2021-08-24 12:17:31 -04:00
2021-08-26 12:34:18 -04:00
// Strikethrough
+ SVerticalBox : : Slot ( )
. AutoHeight ( )
[
SNew ( SHorizontalBox )
2021-08-24 12:17:31 -04:00
2021-08-26 12:34:18 -04:00
// Checkbox
+ SHorizontalBox : : Slot ( )
. AutoWidth ( )
[
SNew ( SCheckBox )
. Style ( & FAppStyle : : Get ( ) . GetWidgetStyle < FCheckBoxStyle > ( " SimplifiedCheckbox " ) )
. OnCheckStateChanged_Lambda ( [ this ] ( ECheckBoxState NewState )
{
if ( NewState = = ECheckBoxState : : Checked )
{
2022-04-22 15:52:31 -04:00
SampleTextStyle . SetStrikeBrush ( * FAppStyle : : Get ( ) . GetBrush ( " DefaultTextUnderline " ) ) ;
2021-08-26 12:34:18 -04:00
}
else
{
2022-04-22 15:52:31 -04:00
SampleTextStyle . SetStrikeBrush ( * FAppStyle : : Get ( ) . GetBrush ( " NoBrush " ) ) ;
2021-08-26 12:34:18 -04:00
}
2021-08-24 12:17:31 -04:00
2021-08-26 12:34:18 -04:00
SampleTextBlock - > SetTextStyle ( & SampleTextStyle ) ;
} )
]
2021-08-24 12:17:31 -04:00
2021-08-26 12:34:18 -04:00
// Name
+ SHorizontalBox : : Slot ( )
. AutoWidth ( )
. Padding ( 8.0f , 0.0f )
[
SNew ( STextBlock ) . Text ( FText : : FromString ( TEXT ( " Strikethrough " ) ) )
]
]
2021-08-24 12:17:31 -04:00
2021-08-26 12:34:18 -04:00
// Underline
+ SVerticalBox : : Slot ( )
. AutoHeight ( )
[
SNew ( SHorizontalBox )
2021-08-24 12:17:31 -04:00
2021-08-26 12:34:18 -04:00
// Checkbox
+ SHorizontalBox : : Slot ( )
. AutoWidth ( )
[
SNew ( SCheckBox )
. Style ( & FAppStyle : : Get ( ) . GetWidgetStyle < FCheckBoxStyle > ( " SimplifiedCheckbox " ) )
. OnCheckStateChanged_Lambda ( [ this , & OutFlags ] ( ECheckBoxState NewState )
{
if ( NewState = = ECheckBoxState : : Checked )
{
2022-04-22 15:52:31 -04:00
SampleTextStyle . SetUnderlineBrush ( * FAppStyle : : Get ( ) . GetBrush ( " DefaultTextUnderline " ) ) ;
2021-08-26 12:34:18 -04:00
EnumAddFlags ( OutFlags , EFontImportFlags : : EnableUnderline ) ;
}
else
{
2022-04-22 15:52:31 -04:00
SampleTextStyle . SetUnderlineBrush ( * FAppStyle : : Get ( ) . GetBrush ( " NoBrush " ) ) ;
2021-08-26 12:34:18 -04:00
EnumRemoveFlags ( OutFlags , EFontImportFlags : : EnableUnderline ) ;
}
2021-08-24 12:17:31 -04:00
2021-08-26 12:34:18 -04:00
SampleTextBlock - > SetTextStyle ( & SampleTextStyle ) ;
} )
]
2021-08-24 12:17:31 -04:00
2021-08-26 12:34:18 -04:00
// Name
+ SHorizontalBox : : Slot ( )
. AutoWidth ( )
. Padding ( 8.0f , 0.0f )
[
SNew ( STextBlock ) . Text ( FText : : FromString ( TEXT ( " Underline " ) ) )
]
]
]
2021-08-24 12:17:31 -04:00
2021-08-26 12:34:18 -04:00
// Color
+ SGridPanel : : Slot ( 1 , 1 )
. Padding ( 8.0f )
[
SNew ( SVerticalBox )
2021-08-24 12:17:31 -04:00
2021-08-26 12:34:18 -04:00
// Name
+ SVerticalBox : : Slot ( )
. AutoHeight ( )
[
SNew ( STextBlock ) . Text ( FText : : FromString ( TEXT ( " Color " ) ) )
]
2021-08-24 12:17:31 -04:00
2021-08-26 12:34:18 -04:00
// Color picker button
+ SVerticalBox : : Slot ( )
. AutoHeight ( )
. HAlign ( HAlign_Left )
[
SNew ( SButton )
2022-04-22 15:52:31 -04:00
. ButtonStyle ( FAppStyle : : Get ( ) , " Menu.Button " )
2021-08-26 12:34:18 -04:00
. OnClicked_Raw ( this , & FSlateFontDlgWindow : : OpenColorPicker )
[
SNew ( SOverlay )
2021-08-24 12:17:31 -04:00
2021-08-26 12:34:18 -04:00
+ SOverlay : : Slot ( )
. Padding ( FMargin ( 0.0f , 0.0f , 0.0f , 4.0f ) )
. HAlign ( HAlign_Center )
. VAlign ( VAlign_Bottom )
[
SAssignNew ( ColorIconText , STextBlock )
. Text ( LOCTEXT ( " ColorLabel " , " A " ) )
]
2021-08-24 12:17:31 -04:00
2021-08-26 12:34:18 -04:00
+ SOverlay : : Slot ( )
. HAlign ( HAlign_Center )
. VAlign ( VAlign_Bottom )
[
SNew ( SColorBlock )
. Color_Lambda ( [ this ] ( ) { return FontColor ; } )
. Size ( FVector2D ( 20.0f , 6.0f ) )
]
]
]
]
2021-08-24 12:17:31 -04:00
2021-08-26 12:34:18 -04:00
// Sample Text
+ SGridPanel : : Slot ( 2 , 1 )
. Padding ( 8.0f )
[
SNew ( SBox )
. MaxDesiredHeight ( 200 )
. MaxDesiredWidth ( 600 )
[
SAssignNew ( SampleTextBlock , STextBlock )
. TextStyle ( & SampleTextStyle )
. Text ( FText : : FromString ( TEXT ( " Sample Text " ) ) )
]
]
2021-08-24 12:17:31 -04:00
2021-08-26 12:34:18 -04:00
// OK / Cancel buttons
+ SGridPanel : : Slot ( 2 , 2 )
. Padding ( 8.0f )
. HAlign ( EHorizontalAlignment : : HAlign_Right )
[
SNew ( SHorizontalBox )
2021-08-24 12:17:31 -04:00
2021-08-26 12:34:18 -04:00
// OK Button
+ SHorizontalBox : : Slot ( )
. AutoWidth ( )
. Padding ( 8.0f , 0.0f )
[
SNew ( SButton )
. Text ( FText : : FromString ( TEXT ( " OK " ) ) )
. OnClicked_Lambda ( [ this , & OutSuccess ] ( ) - > FReply
{
OutSuccess = true ;
Window - > RequestDestroyWindow ( ) ;
return FReply : : Handled ( ) ;
} )
]
2021-08-24 12:17:31 -04:00
2021-08-26 12:34:18 -04:00
// Cancel Button
+ SHorizontalBox : : Slot ( )
. AutoWidth ( )
. Padding ( 8.0f , 0.0f )
[
SNew ( SButton )
. Text ( FText : : FromString ( TEXT ( " Cancel " ) ) )
. OnClicked_Lambda ( [ this , & OutSuccess ] ( ) - > FReply
{
OutSuccess = false ;
Window - > RequestDestroyWindow ( ) ;
return FReply : : Handled ( ) ;
} )
]
]
] ;
2021-08-24 12:17:31 -04:00
2021-08-26 12:34:18 -04:00
FSlateApplication : : Get ( ) . AddModalWindow ( Window . ToSharedRef ( ) , FGlobalTabmanager : : Get ( ) - > GetRootWindow ( ) ) ;
2021-08-24 12:17:31 -04:00
}
END_SLATE_FUNCTION_BUILD_OPTIMIZATION
# undef LOCTEXT_NAMESPACE