1166 lines
38 KiB
C++
1166 lines
38 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "FontEditor.h"
|
|
|
|
#include "Containers/Array.h"
|
|
#include "Containers/EnumAsByte.h"
|
|
#include "Containers/List.h"
|
|
#include "CoreGlobals.h"
|
|
#include "Delegates/Delegate.h"
|
|
#include "DesktopPlatformModule.h"
|
|
#include "DetailsViewArgs.h"
|
|
#include "Editor.h"
|
|
#include "Editor/EditorEngine.h"
|
|
#include "EditorReimportHandler.h"
|
|
#include "Engine/Engine.h"
|
|
#include "Engine/EngineTypes.h"
|
|
#include "Engine/Font.h"
|
|
#include "Engine/FontFace.h"
|
|
#include "Engine/FontImportOptions.h"
|
|
#include "Engine/Texture.h"
|
|
#include "Engine/Texture2D.h"
|
|
#include "Engine/TextureDefines.h"
|
|
#include "Exporters/Exporter.h"
|
|
#include "Exporters/TextureExporterTGA.h"
|
|
#include "Factories/Factory.h"
|
|
#include "Factories/FontFactory.h"
|
|
#include "Factories/TextureFactory.h"
|
|
#include "Factories/TrueTypeFontFactory.h"
|
|
#include "FontEditorModule.h"
|
|
#include "Framework/Application/SlateApplication.h"
|
|
#include "Framework/Commands/Commands.h"
|
|
#include "Framework/Commands/InputChord.h"
|
|
#include "Framework/Commands/UIAction.h"
|
|
#include "Framework/Commands/UICommandInfo.h"
|
|
#include "Framework/Commands/UICommandList.h"
|
|
#include "Framework/MultiBox/MultiBoxBuilder.h"
|
|
#include "Framework/MultiBox/MultiBoxExtender.h"
|
|
#include "HAL/PlatformCrt.h"
|
|
#include "HAL/PlatformMisc.h"
|
|
#include "IDesktopPlatform.h"
|
|
#include "IDetailsView.h"
|
|
#include "Internationalization/Internationalization.h"
|
|
#include "Layout/Margin.h"
|
|
#include "Logging/LogMacros.h"
|
|
#include "Math/UnrealMathSSE.h"
|
|
#include "Misc/AssertionMacros.h"
|
|
#include "Misc/Attribute.h"
|
|
#include "Misc/FileHelper.h"
|
|
#include "Misc/MessageDialog.h"
|
|
#include "Misc/Paths.h"
|
|
#include "Modules/ModuleManager.h"
|
|
#include "PropertyEditorDelegates.h"
|
|
#include "PropertyEditorModule.h"
|
|
#include "SCompositeFontEditor.h"
|
|
#include "SFontEditorViewport.h"
|
|
#include "Selection.h"
|
|
#include "SlotBase.h"
|
|
#include "Styling/AppStyle.h"
|
|
#include "Subsystems/ImportSubsystem.h"
|
|
#include "Templates/Casts.h"
|
|
#include "Textures/SlateIcon.h"
|
|
#include "Toolkits/AssetEditorToolkit.h"
|
|
#include "Types/SlateEnums.h"
|
|
#include "UObject/ObjectMacros.h"
|
|
#include "UObject/ObjectPtr.h"
|
|
#include "UObject/UObjectGlobals.h"
|
|
#include "UObject/UnrealNames.h"
|
|
#include "UObject/UnrealType.h"
|
|
#include "Widgets/Colors/SColorPicker.h"
|
|
#include "Widgets/DeclarativeSyntaxSupport.h"
|
|
#include "Widgets/Docking/SDockTab.h"
|
|
#include "Widgets/Input/SCheckBox.h"
|
|
#include "Widgets/Input/SEditableTextBox.h"
|
|
#include "Widgets/Input/SNumericEntryBox.h"
|
|
#include "Widgets/SBoxPanel.h"
|
|
#include "Widgets/Text/STextBlock.h"
|
|
|
|
#define LOCTEXT_NAMESPACE "FontEditor"
|
|
|
|
DEFINE_LOG_CATEGORY_STATIC(LogFontEditor, Log, All);
|
|
|
|
FString FFontEditor::LastPath;
|
|
|
|
const FName FFontEditor::TexturePagesViewportTabId( TEXT( "FontEditor_TexturePagesViewport" ) );
|
|
const FName FFontEditor::CompositeFontEditorTabId( TEXT( "FontEditor_CompositeFontEditor" ) );
|
|
const FName FFontEditor::PreviewTabId( TEXT( "FontEditor_FontPreview" ) );
|
|
const FName FFontEditor::PropertiesTabId( TEXT( "FontEditor_FontProperties" ) );
|
|
const FName FFontEditor::PagePropertiesTabId( TEXT( "FontEditor_FontPageProperties" ) );
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
FFontEditorCommands
|
|
-----------------------------------------------------------------------------*/
|
|
|
|
class FFontEditorCommands : public TCommands<FFontEditorCommands>
|
|
{
|
|
public:
|
|
/** Constructor */
|
|
FFontEditorCommands()
|
|
: TCommands<FFontEditorCommands>("FontEditor", NSLOCTEXT("Contexts", "FontEditor", "Font Editor"), NAME_None, FAppStyle::GetAppStyleSetName())
|
|
{
|
|
}
|
|
|
|
/** Imports a single font page */
|
|
TSharedPtr<FUICommandInfo> Update;
|
|
|
|
/** Imports all font pages */
|
|
TSharedPtr<FUICommandInfo> UpdateAll;
|
|
|
|
/** Exports a single font page */
|
|
TSharedPtr<FUICommandInfo> ExportPage;
|
|
|
|
/** Exports all font pages */
|
|
TSharedPtr<FUICommandInfo> ExportAllPages;
|
|
|
|
/** Spawns a color picker for changing the background color of the font preview viewport */
|
|
TSharedPtr<FUICommandInfo> FontBackgroundColor;
|
|
|
|
/** Spawns a color picker for changing the foreground color of the font preview viewport */
|
|
TSharedPtr<FUICommandInfo> FontForegroundColor;
|
|
|
|
/** Initialize commands */
|
|
virtual void RegisterCommands() override;
|
|
};
|
|
|
|
void FFontEditorCommands::RegisterCommands()
|
|
{
|
|
UI_COMMAND(Update, "Update", "Imports a texture to replace the currently selected page.", EUserInterfaceActionType::Button, FInputChord());
|
|
UI_COMMAND(UpdateAll, "Update All", "Imports a set of textures to replace all pages.", EUserInterfaceActionType::Button, FInputChord());
|
|
UI_COMMAND(ExportPage, "Export", "Exports the currently selected page.", EUserInterfaceActionType::Button, FInputChord());
|
|
UI_COMMAND(ExportAllPages, "Export All", "Exports all pages.", EUserInterfaceActionType::Button, FInputChord());
|
|
|
|
UI_COMMAND(FontBackgroundColor, "Background", "Changes the background color of the previewer.", EUserInterfaceActionType::Button, FInputChord());
|
|
UI_COMMAND(FontForegroundColor, "Foreground", "Changes the foreground color of the previewer.", EUserInterfaceActionType::Button, FInputChord());
|
|
}
|
|
|
|
void FFontEditor::RegisterTabSpawners(const TSharedRef<class FTabManager>& InTabManager)
|
|
{
|
|
WorkspaceMenuCategory = InTabManager->AddLocalWorkspaceMenuCategory(LOCTEXT("WorkspaceMenu_FontEditor", "Font Editor"));
|
|
auto WorkspaceMenuCategoryRef = WorkspaceMenuCategory.ToSharedRef();
|
|
|
|
FAssetEditorToolkit::RegisterTabSpawners(InTabManager);
|
|
|
|
InTabManager->RegisterTabSpawner( TexturePagesViewportTabId, FOnSpawnTab::CreateSP(this, &FFontEditor::SpawnTab_TexturePagesViewport) )
|
|
.SetDisplayName( LOCTEXT("TexturePagesViewportTab", "Texture Pages") )
|
|
.SetGroup(WorkspaceMenuCategoryRef)
|
|
.SetIcon(FSlateIcon(FAppStyle::GetAppStyleSetName(), "LevelEditor.Tabs.Viewports"))
|
|
.SetMenuType( TAttribute<ETabSpawnerMenuType::Type>::Create(TAttribute<ETabSpawnerMenuType::Type>::FGetter::CreateSP(this, &FFontEditor::GetTabSpawnerMenuType, TexturePagesViewportTabId)) );
|
|
|
|
InTabManager->RegisterTabSpawner( CompositeFontEditorTabId, FOnSpawnTab::CreateSP(this, &FFontEditor::SpawnTab_CompositeFontEditor) )
|
|
.SetDisplayName( LOCTEXT("CompositeFontEditorTab", "Composite Font") )
|
|
.SetGroup(WorkspaceMenuCategoryRef)
|
|
.SetIcon(FSlateIcon(FAppStyle::GetAppStyleSetName(), "FontEditor.Tabs.PageProperties"))
|
|
.SetMenuType( TAttribute<ETabSpawnerMenuType::Type>::Create(TAttribute<ETabSpawnerMenuType::Type>::FGetter::CreateSP(this, &FFontEditor::GetTabSpawnerMenuType, CompositeFontEditorTabId)) );
|
|
|
|
InTabManager->RegisterTabSpawner( PreviewTabId, FOnSpawnTab::CreateSP(this, &FFontEditor::SpawnTab_Preview) )
|
|
.SetDisplayName( LOCTEXT("PreviewTab", "Preview") )
|
|
.SetGroup(WorkspaceMenuCategoryRef)
|
|
.SetIcon(FSlateIcon(FAppStyle::GetAppStyleSetName(), "FontEditor.Tabs.Preview"));
|
|
|
|
InTabManager->RegisterTabSpawner( PropertiesTabId, FOnSpawnTab::CreateSP(this, &FFontEditor::SpawnTab_Properties) )
|
|
.SetDisplayName( LOCTEXT("PropertiesTabId", "Details") )
|
|
.SetGroup(WorkspaceMenuCategoryRef)
|
|
.SetIcon(FSlateIcon(FAppStyle::GetAppStyleSetName(), "LevelEditor.Tabs.Details"));
|
|
|
|
InTabManager->RegisterTabSpawner( PagePropertiesTabId,FOnSpawnTab::CreateSP(this, &FFontEditor::SpawnTab_PageProperties) )
|
|
.SetDisplayName( LOCTEXT("PagePropertiesTab", "Page Details") )
|
|
.SetGroup(WorkspaceMenuCategoryRef)
|
|
.SetIcon(FSlateIcon(FAppStyle::GetAppStyleSetName(), "FontEditor.Tabs.PageProperties"))
|
|
.SetMenuType( TAttribute<ETabSpawnerMenuType::Type>::Create(TAttribute<ETabSpawnerMenuType::Type>::FGetter::CreateSP(this, &FFontEditor::GetTabSpawnerMenuType, PagePropertiesTabId)) );
|
|
}
|
|
|
|
void FFontEditor::UnregisterTabSpawners(const TSharedRef<class FTabManager>& InTabManager)
|
|
{
|
|
FAssetEditorToolkit::UnregisterTabSpawners(InTabManager);
|
|
|
|
InTabManager->UnregisterTabSpawner( TexturePagesViewportTabId );
|
|
InTabManager->UnregisterTabSpawner( CompositeFontEditorTabId );
|
|
InTabManager->UnregisterTabSpawner( PreviewTabId );
|
|
InTabManager->UnregisterTabSpawner( PropertiesTabId );
|
|
InTabManager->UnregisterTabSpawner( PagePropertiesTabId );
|
|
}
|
|
|
|
FFontEditor::FFontEditor()
|
|
: Font(nullptr)
|
|
, TGAExporter(nullptr)
|
|
, Factory(nullptr)
|
|
{
|
|
}
|
|
|
|
FFontEditor::~FFontEditor()
|
|
{
|
|
FReimportManager::Instance()->OnPostReimport().RemoveAll(this);
|
|
|
|
UEditorEngine* Editor = (UEditorEngine*)GEngine;
|
|
if (Editor != NULL)
|
|
{
|
|
Editor->UnregisterForUndo(this);
|
|
Editor->GetEditorSubsystem<UImportSubsystem>()->OnAssetReimport.RemoveAll(this);
|
|
}
|
|
}
|
|
|
|
void FFontEditor::InitFontEditor(const EToolkitMode::Type Mode, const TSharedPtr< class IToolkitHost >& InitToolkitHost, UObject* ObjectToEdit)
|
|
{
|
|
FReimportManager::Instance()->OnPostReimport().AddRaw(this, &FFontEditor::OnPostReimport);
|
|
|
|
// Register to be notified when an object is reimported.
|
|
GEditor->GetEditorSubsystem<UImportSubsystem>()->OnAssetReimport.AddSP(this, &FFontEditor::OnObjectReimported);
|
|
|
|
FCoreUObjectDelegates::OnObjectPropertyChanged.AddSP(this, &FFontEditor::OnObjectPropertyChanged);
|
|
|
|
Font = CastChecked<UFont>(ObjectToEdit);
|
|
|
|
// Support undo/redo
|
|
Font->SetFlags(RF_Transactional);
|
|
|
|
// Create a TGA exporter
|
|
TGAExporter = NewObject<UTextureExporterTGA>();
|
|
// And our importer
|
|
Factory = NewObject<UTextureFactory>();
|
|
// Set the defaults
|
|
Factory->Blending = BLEND_Opaque;
|
|
Factory->ShadingModel = MSM_Unlit;
|
|
Factory->bDeferCompression = true;
|
|
Factory->MipGenSettings = TMGS_NoMipmaps;
|
|
|
|
UEditorEngine* Editor = (UEditorEngine*)GEngine;
|
|
if (Editor != NULL)
|
|
{
|
|
Editor->RegisterForUndo(this);
|
|
}
|
|
// Register our commands. This will only register them if not previously registered
|
|
FFontEditorCommands::Register();
|
|
|
|
BindCommands();
|
|
|
|
CreateInternalWidgets();
|
|
|
|
const TSharedRef<FTabManager::FLayout> StandaloneDefaultLayout = FTabManager::NewLayout("Standalone_FontEditor_Layout_v4")
|
|
->AddArea
|
|
(
|
|
FTabManager::NewPrimaryArea() ->SetOrientation( Orient_Vertical )
|
|
->Split
|
|
(
|
|
FTabManager::NewSplitter() ->SetOrientation(Orient_Horizontal) ->SetSizeCoefficient(0.9f)
|
|
->Split
|
|
(
|
|
FTabManager::NewSplitter() ->SetOrientation(Orient_Vertical) ->SetSizeCoefficient(0.65f)
|
|
->Split
|
|
(
|
|
FTabManager::NewStack() ->SetSizeCoefficient(0.85f)
|
|
->AddTab( TexturePagesViewportTabId, ETabState::OpenedTab )
|
|
->AddTab( CompositeFontEditorTabId, ETabState::OpenedTab )
|
|
)
|
|
->Split
|
|
(
|
|
FTabManager::NewStack() ->SetSizeCoefficient(0.15f)
|
|
->AddTab( PreviewTabId, ETabState::OpenedTab )
|
|
)
|
|
)
|
|
->Split
|
|
(
|
|
FTabManager::NewSplitter() ->SetOrientation(Orient_Vertical) ->SetSizeCoefficient(0.35f)
|
|
->Split
|
|
(
|
|
FTabManager::NewStack() ->SetSizeCoefficient(0.5f)
|
|
->AddTab( PropertiesTabId, ETabState::OpenedTab )
|
|
)
|
|
->Split
|
|
(
|
|
FTabManager::NewStack() ->SetSizeCoefficient(0.5f)
|
|
->AddTab( PagePropertiesTabId, ETabState::OpenedTab )
|
|
)
|
|
)
|
|
)
|
|
);
|
|
|
|
const bool bCreateDefaultStandaloneMenu = true;
|
|
const bool bCreateDefaultToolbar = true;
|
|
FAssetEditorToolkit::InitAssetEditor(Mode, InitToolkitHost, FontEditorAppIdentifier, StandaloneDefaultLayout, bCreateDefaultStandaloneMenu, bCreateDefaultToolbar, ObjectToEdit);
|
|
|
|
IFontEditorModule* FontEditorModule = &FModuleManager::LoadModuleChecked<IFontEditorModule>("FontEditor");
|
|
AddMenuExtender(FontEditorModule->GetMenuExtensibilityManager()->GetAllExtenders(GetToolkitCommands(), GetEditingObjects()));
|
|
|
|
ExtendToolbar();
|
|
RegenerateMenusAndToolbars();
|
|
|
|
UpdateLayout();
|
|
|
|
// @todo toolkit world centric editing
|
|
/*if(IsWorldCentricAssetEditor())
|
|
{
|
|
SpawnToolkitTab(GetToolbarTabId(), FString(), EToolkitTabSpot::ToolBar);
|
|
SpawnToolkitTab(TexturePagesViewportTabId, FString(), EToolkitTabSpot::Viewport);
|
|
SpawnToolkitTab(CompositeFontEditorTabId, FString(), EToolkitTabSpot::Viewport);
|
|
SpawnToolkitTab(PreviewTabId, FString(), EToolkitTabSpot::Viewport);
|
|
SpawnToolkitTab(PropertiesTabId, FString(), EToolkitTabSpot::Details);
|
|
SpawnToolkitTab(PagePropertiesTabId, FString(), EToolkitTabSpot::Details);
|
|
}*/
|
|
}
|
|
|
|
UFont* FFontEditor::GetFont() const
|
|
{
|
|
return Font;
|
|
}
|
|
|
|
void FFontEditor::SetSelectedPage(int32 PageIdx)
|
|
{
|
|
TArray<UObject*> PagePropertyObjects;
|
|
if (Font->Textures.IsValidIndex(PageIdx))
|
|
{
|
|
PagePropertyObjects.Add(Font->Textures[PageIdx]);
|
|
}
|
|
FontPageProperties->SetObjects(PagePropertyObjects);
|
|
}
|
|
|
|
FName FFontEditor::GetToolkitFName() const
|
|
{
|
|
return FName("FontEditor");
|
|
}
|
|
|
|
FText FFontEditor::GetBaseToolkitName() const
|
|
{
|
|
return LOCTEXT( "AppLabel", "Font Editor" );
|
|
}
|
|
|
|
FString FFontEditor::GetWorldCentricTabPrefix() const
|
|
{
|
|
return LOCTEXT("WorldCentricTabPrefix", "Font ").ToString();
|
|
}
|
|
|
|
FLinearColor FFontEditor::GetWorldCentricTabColorScale() const
|
|
{
|
|
return FLinearColor(0.3f, 0.2f, 0.5f, 0.5f);
|
|
}
|
|
|
|
TSharedRef<SDockTab> FFontEditor::SpawnTab_TexturePagesViewport( const FSpawnTabArgs& Args )
|
|
{
|
|
check( Args.GetTabId().TabType == TexturePagesViewportTabId );
|
|
|
|
TSharedRef<SDockTab> SpawnedTab = SNew(SDockTab)
|
|
.Label(LOCTEXT("TexturePagesViewportTitle", "Texture Pages"))
|
|
[
|
|
FontViewport.ToSharedRef()
|
|
];
|
|
|
|
AddToSpawnedToolPanels( Args.GetTabId().TabType, SpawnedTab );
|
|
|
|
return SpawnedTab;
|
|
}
|
|
|
|
TSharedRef<SDockTab> FFontEditor::SpawnTab_CompositeFontEditor( const FSpawnTabArgs& Args )
|
|
{
|
|
check( Args.GetTabId().TabType == CompositeFontEditorTabId );
|
|
|
|
TSharedRef<SDockTab> SpawnedTab = SNew(SDockTab)
|
|
.Label(LOCTEXT("CompositeFontEditorTitle", "Composite Font"))
|
|
[
|
|
CompositeFontEditor.ToSharedRef()
|
|
];
|
|
|
|
AddToSpawnedToolPanels( Args.GetTabId().TabType, SpawnedTab );
|
|
|
|
return SpawnedTab;
|
|
}
|
|
|
|
TSharedRef<SDockTab> FFontEditor::SpawnTab_Preview( const FSpawnTabArgs& Args )
|
|
{
|
|
check( Args.GetTabId().TabType == PreviewTabId );
|
|
|
|
TSharedRef<SDockTab> SpawnedTab = SNew(SDockTab)
|
|
.Label(LOCTEXT("FontPreviewTitle", "Preview"))
|
|
[
|
|
FontPreview.ToSharedRef()
|
|
];
|
|
|
|
AddToSpawnedToolPanels( Args.GetTabId().TabType, SpawnedTab );
|
|
|
|
return SpawnedTab;
|
|
}
|
|
|
|
TSharedRef<SDockTab> FFontEditor::SpawnTab_Properties( const FSpawnTabArgs& Args )
|
|
{
|
|
check( Args.GetTabId().TabType == PropertiesTabId );
|
|
|
|
TSharedRef<SDockTab> SpawnedTab = SNew(SDockTab)
|
|
.Label(LOCTEXT("FontPropertiesTitle", "Details"))
|
|
[
|
|
FontProperties.ToSharedRef()
|
|
];
|
|
|
|
AddToSpawnedToolPanels( Args.GetTabId().TabType, SpawnedTab );
|
|
|
|
return SpawnedTab;
|
|
}
|
|
|
|
TSharedRef<SDockTab> FFontEditor::SpawnTab_PageProperties( const FSpawnTabArgs& Args )
|
|
{
|
|
check( Args.GetTabId().TabType == PagePropertiesTabId );
|
|
|
|
TSharedRef<SDockTab> SpawnedTab = SNew(SDockTab)
|
|
.Label(LOCTEXT("FontPagePropertiesTitle", "Page Details"))
|
|
[
|
|
FontPageProperties.ToSharedRef()
|
|
];
|
|
|
|
AddToSpawnedToolPanels( Args.GetTabId().TabType, SpawnedTab );
|
|
|
|
return SpawnedTab;
|
|
}
|
|
|
|
void FFontEditor::AddToSpawnedToolPanels( const FName& TabIdentifier, const TSharedRef<SDockTab>& SpawnedTab )
|
|
{
|
|
TWeakPtr<SDockTab>* TabSpot = SpawnedToolPanels.Find(TabIdentifier);
|
|
if (!TabSpot)
|
|
{
|
|
SpawnedToolPanels.Add(TabIdentifier, SpawnedTab);
|
|
}
|
|
else
|
|
{
|
|
check(!TabSpot->IsValid());
|
|
*TabSpot = SpawnedTab;
|
|
}
|
|
}
|
|
|
|
void FFontEditor::AddReferencedObjects(FReferenceCollector& Collector)
|
|
{
|
|
Collector.AddReferencedObject(Font);
|
|
Collector.AddReferencedObject(TGAExporter);
|
|
Collector.AddReferencedObject(Factory);
|
|
}
|
|
|
|
void FFontEditor::OnPreviewTextChanged(const FText& Text)
|
|
{
|
|
FontPreviewWidget->SetPreviewText(Text);
|
|
}
|
|
|
|
TOptional<float> FFontEditor::GetDrawFontScale() const
|
|
{
|
|
return FontPreviewWidget->GetPreviewFontScale();
|
|
}
|
|
|
|
void FFontEditor::OnDrawFontScaleChanged(float InNewValue, ETextCommit::Type CommitType)
|
|
{
|
|
FontPreviewWidget->SetPreviewFontScale(InNewValue);
|
|
}
|
|
|
|
ECheckBoxState FFontEditor::GetDrawFontMetricsState() const
|
|
{
|
|
return (FontPreviewWidget->GetPreviewFontMetrics()) ? ECheckBoxState::Checked : ECheckBoxState::Unchecked;
|
|
}
|
|
|
|
void FFontEditor::OnDrawFontMetricsStateChanged(ECheckBoxState NewState)
|
|
{
|
|
FontPreviewWidget->SetPreviewFontMetrics(NewState == ECheckBoxState::Checked);
|
|
}
|
|
|
|
void FFontEditor::PostUndo(bool bSuccess)
|
|
{
|
|
// Make sure we're using the correct layout, as the undo/redo may have changed the font cache type property
|
|
UpdateLayout();
|
|
|
|
CompositeFontEditor->Refresh();
|
|
}
|
|
|
|
void FFontEditor::NotifyPostChange( const FPropertyChangedEvent& PropertyChangedEvent, class FEditPropertyChain* PropertyThatChanged)
|
|
{
|
|
static const FName FontCacheTypePropertyName = GET_MEMBER_NAME_CHECKED(UFont, FontCacheType);
|
|
static const FName CompositeFontPropertyName = GET_MEMBER_NAME_CHECKED(UFont, CompositeFont);
|
|
static const FName TexturePageWidthName = GET_MEMBER_NAME_CHECKED(FFontImportOptionsData, TexturePageWidth);
|
|
static const FName TexturePageMaxHeightName = GET_MEMBER_NAME_CHECKED(FFontImportOptionsData, TexturePageMaxHeight);
|
|
static const FName DistanceFieldScaleFactorName = GET_MEMBER_NAME_CHECKED(FFontImportOptionsData, DistanceFieldScaleFactor);
|
|
|
|
if(PropertyChangedEvent.Property && PropertyChangedEvent.Property->GetFName() == FontCacheTypePropertyName)
|
|
{
|
|
// Show a warning message, as what we're about to do will destroy any existing data in this font object
|
|
const EAppReturnType::Type DlgResult = FMessageDialog::Open(
|
|
EAppMsgType::YesNo,
|
|
LOCTEXT("ChangeCacheTypeWarningMsg", "Changing the cache type will cause this font to be reinitialized (discarding any existing data).\n\nAre you sure you want to proceed?"),
|
|
LOCTEXT("ChangeCacheTypeWarningTitle", "Really change the font cache type?")
|
|
);
|
|
|
|
bool bSuccessfullyChangedCacheType = false;
|
|
if(DlgResult == EAppReturnType::Yes)
|
|
{
|
|
bSuccessfullyChangedCacheType = RecreateFontObject(Font->FontCacheType);
|
|
}
|
|
|
|
if(bSuccessfullyChangedCacheType)
|
|
{
|
|
CompositeFontEditor->Refresh();
|
|
|
|
// If we changed the font cache type, then we need to update the UI to hide the invalid tabs and spawn the new ones
|
|
UpdateLayout();
|
|
FontProperties->ForceRefresh();
|
|
}
|
|
else
|
|
{
|
|
// Restore the old font cache type
|
|
switch(Font->FontCacheType)
|
|
{
|
|
case EFontCacheType::Offline:
|
|
Font->FontCacheType = EFontCacheType::Runtime;
|
|
break;
|
|
|
|
case EFontCacheType::Runtime:
|
|
Font->FontCacheType = EFontCacheType::Offline;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (PropertyChangedEvent.Property && PropertyChangedEvent.Property->GetFName() == DistanceFieldScaleFactorName)
|
|
{
|
|
const uint32 SignedInt32NumBits = 31;
|
|
const uint32 Log2TexturePageWidth = FMath::CeilLogTwo(Font->ImportOptions.TexturePageWidth);
|
|
const uint32 Log2TexturePageMaxHeight = FMath::CeilLogTwo(Font->ImportOptions.TexturePageMaxHeight);
|
|
const uint32 Log2BytesPerPixel = 2;
|
|
|
|
const int32 MaxDistanceFieldScaleFactor = 1 << ((SignedInt32NumBits - Log2BytesPerPixel - Log2TexturePageWidth - Log2TexturePageMaxHeight) / 2);
|
|
if (Font->ImportOptions.DistanceFieldScaleFactor > MaxDistanceFieldScaleFactor)
|
|
{
|
|
Font->ImportOptions.DistanceFieldScaleFactor = MaxDistanceFieldScaleFactor;
|
|
}
|
|
}
|
|
|
|
if (PropertyChangedEvent.Property && PropertyChangedEvent.Property->GetFName() == TexturePageWidthName)
|
|
{
|
|
const uint32 SignedInt32NumBits = 31;
|
|
const uint32 Log2DistanceFieldScaleFactor = FMath::Max(1U, FMath::CeilLogTwo(Font->ImportOptions.DistanceFieldScaleFactor));
|
|
const uint32 Log2TexturePageMaxHeight = FMath::CeilLogTwo(Font->ImportOptions.TexturePageMaxHeight);
|
|
const uint32 Log2BytesPerPixel = 2;
|
|
|
|
const int32 MaxTexturePageWidth = 1 << (SignedInt32NumBits - Log2BytesPerPixel - 2 * Log2DistanceFieldScaleFactor - Log2TexturePageMaxHeight);
|
|
if (Font->ImportOptions.TexturePageWidth > MaxTexturePageWidth)
|
|
{
|
|
Font->ImportOptions.TexturePageWidth = MaxTexturePageWidth;
|
|
}
|
|
}
|
|
|
|
if (PropertyChangedEvent.Property && PropertyChangedEvent.Property->GetFName() == TexturePageMaxHeightName)
|
|
{
|
|
const uint32 SignedInt32NumBits = 31;
|
|
const uint32 Log2DistanceFieldScaleFactor = FMath::Max(1U, FMath::CeilLogTwo(Font->ImportOptions.DistanceFieldScaleFactor));
|
|
const uint32 Log2TexturePageWidth = FMath::CeilLogTwo(Font->ImportOptions.TexturePageWidth);
|
|
const uint32 Log2BytesPerPixel = 2;
|
|
|
|
const int32 MaxTexturePageMaxHeight = 1 << (SignedInt32NumBits - Log2BytesPerPixel - 2 * Log2DistanceFieldScaleFactor - Log2TexturePageWidth);
|
|
if (Font->ImportOptions.TexturePageMaxHeight > MaxTexturePageMaxHeight)
|
|
{
|
|
Font->ImportOptions.TexturePageMaxHeight = MaxTexturePageMaxHeight;
|
|
}
|
|
}
|
|
|
|
// If we changed a property of the composite font, we need to refresh the composite font editor
|
|
if(PropertyThatChanged && PropertyThatChanged->GetHead()->GetValue()->GetFName() == CompositeFontPropertyName)
|
|
{
|
|
CompositeFontEditor->Refresh();
|
|
}
|
|
|
|
if(Font->FontCacheType == EFontCacheType::Offline)
|
|
{
|
|
FontViewport->RefreshViewport();
|
|
}
|
|
|
|
FontPreviewWidget->RefreshViewport();
|
|
}
|
|
|
|
void FFontEditor::UpdateLayout()
|
|
{
|
|
if(CurrentEditorLayout.IsSet() && CurrentEditorLayout.GetValue() == Font->FontCacheType)
|
|
{
|
|
return;
|
|
}
|
|
|
|
auto CloseTab = [this](const FName& TabName)
|
|
{
|
|
TWeakPtr<SDockTab>* const FoundExistingTab = SpawnedToolPanels.Find(TabName);
|
|
if(FoundExistingTab)
|
|
{
|
|
TSharedPtr<SDockTab> ExistingTab = FoundExistingTab->Pin();
|
|
if(ExistingTab.IsValid())
|
|
{
|
|
ExistingTab->RequestCloseTab();
|
|
}
|
|
}
|
|
};
|
|
|
|
switch(Font->FontCacheType)
|
|
{
|
|
case EFontCacheType::Offline:
|
|
TabManager->TryInvokeTab(TexturePagesViewportTabId);
|
|
TabManager->TryInvokeTab(PagePropertiesTabId);
|
|
CloseTab(CompositeFontEditorTabId);
|
|
break;
|
|
|
|
case EFontCacheType::Runtime:
|
|
TabManager->TryInvokeTab(CompositeFontEditorTabId);
|
|
CloseTab(TexturePagesViewportTabId);
|
|
CloseTab(PagePropertiesTabId);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
CurrentEditorLayout = Font->FontCacheType;
|
|
}
|
|
|
|
ETabSpawnerMenuType::Type FFontEditor::GetTabSpawnerMenuType( FName InTabName ) const
|
|
{
|
|
if( (Font->FontCacheType == EFontCacheType::Offline && (InTabName == CompositeFontEditorTabId)) ||
|
|
(Font->FontCacheType == EFontCacheType::Runtime && (InTabName == TexturePagesViewportTabId || InTabName == PagePropertiesTabId)))
|
|
{
|
|
return ETabSpawnerMenuType::Hidden;
|
|
}
|
|
|
|
return ETabSpawnerMenuType::Enabled;
|
|
}
|
|
|
|
void FFontEditor::CreateInternalWidgets()
|
|
{
|
|
FontViewport =
|
|
SNew(SFontEditorViewport)
|
|
.FontEditor(SharedThis(this));
|
|
|
|
CompositeFontEditor =
|
|
SNew(SCompositeFontEditor)
|
|
.FontEditor(SharedThis(this));
|
|
|
|
FontPreview =
|
|
SNew(SVerticalBox)
|
|
+SVerticalBox::Slot()
|
|
.FillHeight(1.0f)
|
|
.Padding(0.0f, 0.0f, 0.0f, 4.0f)
|
|
[
|
|
SAssignNew(FontPreviewWidget, SFontEditorViewport)
|
|
.FontEditor(SharedThis(this))
|
|
.IsPreview(true)
|
|
]
|
|
+SVerticalBox::Slot()
|
|
.AutoHeight()
|
|
[
|
|
SNew(SHorizontalBox)
|
|
|
|
+SHorizontalBox::Slot()
|
|
[
|
|
SAssignNew(FontPreviewText, SEditableTextBox)
|
|
.Text(LOCTEXT("DefaultPreviewText", "The quick brown fox jumps over the lazy dog"))
|
|
.SelectAllTextWhenFocused(true)
|
|
.OnTextChanged(this, &FFontEditor::OnPreviewTextChanged)
|
|
]
|
|
|
|
+ SHorizontalBox::Slot()
|
|
.AutoWidth()
|
|
[
|
|
SNew(SNumericEntryBox<float>)
|
|
.Value(this, &FFontEditor::GetDrawFontScale)
|
|
.MinValue(1.f)
|
|
.MaxValue(10.f)
|
|
.OnValueCommitted(this, &FFontEditor::OnDrawFontScaleChanged)
|
|
]
|
|
|
|
|
|
+SHorizontalBox::Slot()
|
|
.AutoWidth()
|
|
.Padding(FMargin(2.0f, 0.0f, 0.0f, 0.0f))
|
|
[
|
|
SNew(SCheckBox)
|
|
.IsChecked(this, &FFontEditor::GetDrawFontMetricsState)
|
|
.OnCheckStateChanged(this, &FFontEditor::OnDrawFontMetricsStateChanged)
|
|
.ToolTipText(LOCTEXT("DrawFontMetricsToolTip", "Draw the font metrics (line height, glyph bounding boxes, and base-line) as part of the preview?"))
|
|
[
|
|
SNew(STextBlock)
|
|
.Text(LOCTEXT("DrawFontMetricsLabel", "Draw Font Metrics"))
|
|
]
|
|
]
|
|
];
|
|
|
|
FDetailsViewArgs Args;
|
|
Args.bHideSelectionTip = true;
|
|
Args.NotifyHook = this;
|
|
|
|
FPropertyEditorModule& PropertyModule = FModuleManager::LoadModuleChecked<FPropertyEditorModule>("PropertyEditor");
|
|
FontProperties = PropertyModule.CreateDetailView(Args);
|
|
FontPageProperties = PropertyModule.CreateDetailView(Args);
|
|
|
|
FontProperties->SetIsPropertyVisibleDelegate(FIsPropertyVisible::CreateRaw(this, &FFontEditor::GetIsPropertyVisible));
|
|
FontProperties->SetObject( Font );
|
|
}
|
|
|
|
void FFontEditor::ExtendToolbar()
|
|
{
|
|
struct Local
|
|
{
|
|
static void FillToolbar(FToolBarBuilder& ToolbarBuilder)
|
|
{
|
|
ToolbarBuilder.BeginSection("FontImportExport");
|
|
{
|
|
ToolbarBuilder.AddToolBarButton(FFontEditorCommands::Get().Update);
|
|
ToolbarBuilder.AddToolBarButton(FFontEditorCommands::Get().UpdateAll);
|
|
ToolbarBuilder.AddToolBarButton(FFontEditorCommands::Get().ExportPage);
|
|
ToolbarBuilder.AddToolBarButton(FFontEditorCommands::Get().ExportAllPages);
|
|
}
|
|
ToolbarBuilder.EndSection();
|
|
|
|
ToolbarBuilder.BeginSection("FontPreviewer");
|
|
{
|
|
ToolbarBuilder.AddToolBarButton(FFontEditorCommands::Get().FontBackgroundColor);
|
|
ToolbarBuilder.AddToolBarButton(FFontEditorCommands::Get().FontForegroundColor);
|
|
}
|
|
ToolbarBuilder.EndSection();
|
|
}
|
|
};
|
|
|
|
TSharedPtr<FExtender> ToolbarExtender = MakeShareable(new FExtender);
|
|
|
|
ToolbarExtender->AddToolBarExtension(
|
|
"Asset",
|
|
EExtensionHook::After,
|
|
GetToolkitCommands(),
|
|
FToolBarExtensionDelegate::CreateStatic( &Local::FillToolbar )
|
|
);
|
|
|
|
AddToolbarExtender(ToolbarExtender);
|
|
// AddToSpawnedToolPanels( GetToolbarTabId(), ToolbarTab );
|
|
|
|
IFontEditorModule* FontEditorModule = &FModuleManager::LoadModuleChecked<IFontEditorModule>("FontEditor");
|
|
AddToolbarExtender(FontEditorModule->GetToolBarExtensibilityManager()->GetAllExtenders(GetToolkitCommands(), GetEditingObjects()));
|
|
}
|
|
|
|
void FFontEditor::BindCommands()
|
|
{
|
|
const FFontEditorCommands& Commands = FFontEditorCommands::Get();
|
|
|
|
ToolkitCommands->MapAction(
|
|
Commands.Update,
|
|
FExecuteAction::CreateSP(this, &FFontEditor::OnUpdate),
|
|
FCanExecuteAction::CreateSP(this, &FFontEditor::OnUpdateEnabled));
|
|
|
|
ToolkitCommands->MapAction(
|
|
Commands.UpdateAll,
|
|
FExecuteAction::CreateSP(this, &FFontEditor::OnUpdateAll),
|
|
FCanExecuteAction::CreateSP(this, &FFontEditor::OnUpdateAllEnabled));
|
|
|
|
ToolkitCommands->MapAction(
|
|
Commands.ExportPage,
|
|
FExecuteAction::CreateSP(this, &FFontEditor::OnExport),
|
|
FCanExecuteAction::CreateSP(this, &FFontEditor::OnExportEnabled));
|
|
|
|
ToolkitCommands->MapAction(
|
|
Commands.ExportAllPages,
|
|
FExecuteAction::CreateSP(this, &FFontEditor::OnExportAll),
|
|
FCanExecuteAction::CreateSP(this, &FFontEditor::OnExportAllEnabled));
|
|
|
|
ToolkitCommands->MapAction(
|
|
Commands.FontBackgroundColor,
|
|
FExecuteAction::CreateSP(this, &FFontEditor::OnBackgroundColor),
|
|
FCanExecuteAction::CreateSP(this, &FFontEditor::OnBackgroundColorEnabled));
|
|
|
|
ToolkitCommands->MapAction(
|
|
Commands.FontForegroundColor,
|
|
FExecuteAction::CreateSP(this, &FFontEditor::OnForegroundColor),
|
|
FCanExecuteAction::CreateSP(this, &FFontEditor::OnForegroundColorEnabled));
|
|
}
|
|
|
|
void FFontEditor::OnUpdate()
|
|
{
|
|
int32 CurrentSelectedPage = FontViewport->GetCurrentSelectedPage();
|
|
|
|
if (CurrentSelectedPage > INDEX_NONE)
|
|
{
|
|
TArray<FString> OpenFilenames;
|
|
IDesktopPlatform* DesktopPlatform = FDesktopPlatformModule::Get();
|
|
bool bOpened = false;
|
|
if ( DesktopPlatform )
|
|
{
|
|
bOpened = DesktopPlatform->OpenFileDialog(
|
|
FSlateApplication::Get().FindBestParentWindowHandleForDialogs(nullptr),
|
|
LOCTEXT("ImportDialogTitle", "Import").ToString(),
|
|
LastPath,
|
|
TEXT(""),
|
|
TEXT("TGA Files (*.tga)|*.tga"),
|
|
EFileDialogFlags::None,
|
|
OpenFilenames
|
|
);
|
|
}
|
|
|
|
if (bOpened)
|
|
{
|
|
LastPath = FPaths::GetPath(OpenFilenames[0]);
|
|
// Use the common routine for importing the texture
|
|
if (ImportPage(CurrentSelectedPage, *OpenFilenames[0]) == false)
|
|
{
|
|
FFormatNamedArguments Args;
|
|
Args.Add( TEXT("CurrentPageNumber"), CurrentSelectedPage );
|
|
Args.Add( TEXT("Filename"), FText::FromString( OpenFilenames[0] ) );
|
|
|
|
// Show an error to the user
|
|
FMessageDialog::Open( EAppMsgType::Ok, FText::Format( LOCTEXT("FailedToUpdateFontPage", "Failed to update the font page ({CurrentPageNumber}) with texture ({Filename})"), Args ) );
|
|
}
|
|
}
|
|
|
|
GEditor->GetSelectedObjects()->DeselectAll();
|
|
GEditor->GetSelectedObjects()->Select(Font->Textures[CurrentSelectedPage]);
|
|
|
|
FontViewport->RefreshViewport();
|
|
FontPreviewWidget->RefreshViewport();
|
|
}
|
|
}
|
|
|
|
bool FFontEditor::OnUpdateEnabled() const
|
|
{
|
|
return Font->FontCacheType == EFontCacheType::Offline && FontViewport->GetCurrentSelectedPage() != INDEX_NONE;
|
|
}
|
|
|
|
void FFontEditor::OnUpdateAll()
|
|
{
|
|
int32 CurrentSelectedPage = FontViewport->GetCurrentSelectedPage();
|
|
|
|
// Open dialog so user can chose which directory to export to
|
|
IDesktopPlatform* DesktopPlatform = FDesktopPlatformModule::Get();
|
|
if ( DesktopPlatform )
|
|
{
|
|
FString FolderName;
|
|
const FString Title = FText::Format( NSLOCTEXT("UnrealEd", "Save_F", "Save: {0}"), FText::FromString(Font->GetName()) ).ToString();
|
|
const bool bFolderSelected = DesktopPlatform->OpenDirectoryDialog(
|
|
FSlateApplication::Get().FindBestParentWindowHandleForDialogs(nullptr),
|
|
Title,
|
|
LastPath,
|
|
FolderName
|
|
);
|
|
|
|
if ( bFolderSelected )
|
|
{
|
|
LastPath = FolderName;
|
|
// Try to import each file into the corresponding page
|
|
for (int32 Index = 0; Index < Font->Textures.Num(); ++Index)
|
|
{
|
|
// Create a name for the file based off of the font name and page number
|
|
FString FileName = FString::Printf(TEXT("%s/%s_Page_%d.tga"), *LastPath, *Font->GetName(), Index);
|
|
if (ImportPage(Index, *FileName) == false)
|
|
{
|
|
FFormatNamedArguments Args;
|
|
Args.Add( TEXT("CurrentPageNumber"), Index );
|
|
Args.Add( TEXT("Filename"), FText::FromString( FileName ) );
|
|
|
|
// Show an error to the user
|
|
FMessageDialog::Open( EAppMsgType::Ok, FText::Format( LOCTEXT("FailedToUpdateFontPage", "Failed to update the font page ({CurrentPageNumber}) with texture ({Filename})"), Args ) );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
GEditor->GetSelectedObjects()->DeselectAll();
|
|
if (CurrentSelectedPage != INDEX_NONE)
|
|
{
|
|
GEditor->GetSelectedObjects()->Select(Font->Textures[CurrentSelectedPage]);
|
|
}
|
|
|
|
FontViewport->RefreshViewport();
|
|
FontPreviewWidget->RefreshViewport();
|
|
}
|
|
|
|
bool FFontEditor::OnUpdateAllEnabled() const
|
|
{
|
|
return Font->FontCacheType == EFontCacheType::Offline;
|
|
}
|
|
|
|
void FFontEditor::OnExport()
|
|
{
|
|
int32 CurrentSelectedPage = FontViewport->GetCurrentSelectedPage();
|
|
|
|
if (CurrentSelectedPage > INDEX_NONE)
|
|
{
|
|
// Open dialog so user can chose which directory to export to
|
|
IDesktopPlatform* DesktopPlatform = FDesktopPlatformModule::Get();
|
|
if ( DesktopPlatform )
|
|
{
|
|
FString FolderName;
|
|
const FString Title = FText::Format( NSLOCTEXT("UnrealEd", "Save_F", "Save: {0}"), FText::FromString(Font->GetName()) ).ToString();
|
|
const bool bFolderSelected = DesktopPlatform->OpenDirectoryDialog(
|
|
FSlateApplication::Get().FindBestParentWindowHandleForDialogs(nullptr),
|
|
Title,
|
|
LastPath,
|
|
FolderName
|
|
);
|
|
|
|
if ( bFolderSelected )
|
|
{
|
|
LastPath = FolderName;
|
|
// Create a name for the file based off of the font name and page number
|
|
FString FileName = FString::Printf(TEXT("%s/%s_Page_%d.tga"), *LastPath, *Font->GetName(), CurrentSelectedPage);
|
|
|
|
// Create that file with the texture data
|
|
UExporter::ExportToFile(Font->Textures[CurrentSelectedPage], TGAExporter, *FileName, false);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
bool FFontEditor::OnExportEnabled() const
|
|
{
|
|
return Font->FontCacheType == EFontCacheType::Offline && FontViewport->GetCurrentSelectedPage() != INDEX_NONE;
|
|
}
|
|
|
|
void FFontEditor::OnExportAll()
|
|
{
|
|
// Open dialog so user can chose which directory to export to
|
|
IDesktopPlatform* DesktopPlatform = FDesktopPlatformModule::Get();
|
|
if ( DesktopPlatform )
|
|
{
|
|
FString FolderName;
|
|
const FString Title = FText::Format( NSLOCTEXT("UnrealEd", "Save_F", "Save: {0}"), FText::FromString(Font->GetName()) ).ToString();
|
|
const bool bFolderSelected = DesktopPlatform->OpenDirectoryDialog(
|
|
FSlateApplication::Get().FindBestParentWindowHandleForDialogs(nullptr),
|
|
Title,
|
|
LastPath,
|
|
FolderName
|
|
);
|
|
|
|
if ( bFolderSelected )
|
|
{
|
|
LastPath = FolderName;
|
|
// Loop through exporting each file to the specified directory
|
|
for (int32 Index = 0; Index < Font->Textures.Num(); ++Index)
|
|
{
|
|
// Create a name for the file based off of the font name and page number
|
|
FString FileName = FString::Printf(TEXT("%s/%s_Page_%d.tga"), *LastPath, *Font->GetName(), Index);
|
|
|
|
// Create that file with the texture data
|
|
UExporter::ExportToFile(Font->Textures[Index], TGAExporter, *FileName, false);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
bool FFontEditor::OnExportAllEnabled() const
|
|
{
|
|
return Font->FontCacheType == EFontCacheType::Offline;
|
|
}
|
|
|
|
void FFontEditor::OnBackgroundColor()
|
|
{
|
|
TWeakPtr<SFontEditorViewport> WeakFontPreviewWidget = FontPreviewWidget;
|
|
|
|
FColorPickerArgs PickerArgs;
|
|
PickerArgs.bIsModal = true;
|
|
PickerArgs.ParentWidget = FontPreview;
|
|
PickerArgs.bUseAlpha = true;
|
|
PickerArgs.bClampValue = true;
|
|
PickerArgs.DisplayGamma = TAttribute<float>::Create( TAttribute<float>::FGetter::CreateUObject(GEngine, &UEngine::GetDisplayGamma) );
|
|
PickerArgs.InitialColor = FontPreviewWidget->GetPreviewBackgroundColor();
|
|
PickerArgs.OnColorCommitted = FOnLinearColorValueChanged::CreateLambda([WeakFontPreviewWidget](FLinearColor NewValue)
|
|
{
|
|
if (TSharedPtr<SFontEditorViewport> PinnedWidget = WeakFontPreviewWidget.Pin())
|
|
{
|
|
PinnedWidget->SetPreviewBackgroundColor(NewValue.ToFColorSRGB());
|
|
}
|
|
});
|
|
|
|
OpenColorPicker(PickerArgs);
|
|
}
|
|
|
|
bool FFontEditor::OnBackgroundColorEnabled() const
|
|
{
|
|
const TWeakPtr<SDockTab>* PreviewTab = SpawnedToolPanels.Find( PreviewTabId );
|
|
return PreviewTab && PreviewTab->IsValid();
|
|
}
|
|
|
|
void FFontEditor::OnForegroundColor()
|
|
{
|
|
TWeakPtr<SFontEditorViewport> WeakFontPreviewWidget = FontPreviewWidget;
|
|
|
|
FColorPickerArgs PickerArgs;
|
|
PickerArgs.bIsModal = true;
|
|
PickerArgs.ParentWidget = FontPreview;
|
|
PickerArgs.bUseAlpha = true;
|
|
PickerArgs.DisplayGamma = TAttribute<float>::Create( TAttribute<float>::FGetter::CreateUObject(GEngine, &UEngine::GetDisplayGamma) );
|
|
PickerArgs.InitialColor = FontPreviewWidget->GetPreviewForegroundColor();
|
|
PickerArgs.OnColorCommitted = FOnLinearColorValueChanged::CreateLambda([WeakFontPreviewWidget](FLinearColor NewValue)
|
|
{
|
|
if (TSharedPtr<SFontEditorViewport> PinnedWidget = WeakFontPreviewWidget.Pin())
|
|
{
|
|
PinnedWidget->SetPreviewForegroundColor(NewValue.ToFColorSRGB());
|
|
}
|
|
});
|
|
|
|
OpenColorPicker(PickerArgs);
|
|
}
|
|
|
|
bool FFontEditor::OnForegroundColorEnabled() const
|
|
{
|
|
const TWeakPtr<SDockTab>* PreviewTab = SpawnedToolPanels.Find( PreviewTabId );
|
|
return PreviewTab && PreviewTab->IsValid();
|
|
}
|
|
|
|
void FFontEditor::OnPostReimport(UObject* InObject, bool bSuccess)
|
|
{
|
|
// Ignore if this is regarding a different object
|
|
if ( InObject != Font )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if ( bSuccess )
|
|
{
|
|
FontViewport->RefreshViewport();
|
|
FontPreviewWidget->RefreshViewport();
|
|
}
|
|
}
|
|
|
|
void FFontEditor::OnObjectPropertyChanged(UObject* InObject, struct FPropertyChangedEvent& InPropertyChangedEvent)
|
|
{
|
|
if (Cast<UFont>(InObject))
|
|
{
|
|
//Force all texts using a font to be refreshed.
|
|
FSlateApplicationBase::Get().InvalidateAllWidgets(false);
|
|
GSlateLayoutGeneration++;
|
|
}
|
|
|
|
if (Cast<UFontFace>(InObject))
|
|
{
|
|
// Refresh the composite font editor when a font face is changed as it may affect our preview
|
|
CompositeFontEditor->Refresh();
|
|
}
|
|
}
|
|
|
|
bool FFontEditor::ImportPage(int32 PageNum, const TCHAR* FileName)
|
|
{
|
|
bool bSuccess = false;
|
|
TArray<uint8> Data;
|
|
|
|
// Read the file into an array
|
|
if (FFileHelper::LoadFileToArray(Data, FileName))
|
|
{
|
|
// Make a const pointer for the API to be happy
|
|
const uint8* DataPtr = Data.GetData();
|
|
|
|
// Create the new texture... note RF_Public because font textures can be referenced directly by material expressions
|
|
UTexture2D* NewPage = (UTexture2D*)Factory->FactoryCreateBinary(UTexture2D::StaticClass(), Font, NAME_None, RF_Public, NULL, TEXT("TGA"), DataPtr, DataPtr + Data.Num(), GWarn);
|
|
|
|
if (NewPage != NULL && Font->Textures.IsValidIndex(PageNum))
|
|
{
|
|
UTexture2D* Texture = Font->Textures[PageNum];
|
|
|
|
// Make sure the sizes are the same
|
|
if (Texture->Source.GetSizeX() == NewPage->Source.GetSizeX() && Texture->Source.GetSizeY() == NewPage->Source.GetSizeY())
|
|
{
|
|
// Set the new texture's settings to match the old texture
|
|
NewPage->CompressionNoAlpha = Texture->CompressionNoAlpha;
|
|
NewPage->CompressionNone = Texture->CompressionNone;
|
|
NewPage->MipGenSettings = Texture->MipGenSettings;
|
|
NewPage->CompressionNoAlpha = Texture->CompressionNoAlpha;
|
|
NewPage->NeverStream = Texture->NeverStream;
|
|
NewPage->CompressionSettings = Texture->CompressionSettings;
|
|
NewPage->Filter = Texture->Filter;
|
|
|
|
// Now compress the texture
|
|
NewPage->PostEditChange();
|
|
|
|
// Replace the existing texture with the new one
|
|
Font->Textures[PageNum] = NewPage;
|
|
|
|
// Dirty the font's package and refresh the content browser to indicate the font's package needs to be saved post-update
|
|
Font->MarkPackageDirty();
|
|
}
|
|
else
|
|
{
|
|
// Tell the user the sizes mismatch
|
|
FMessageDialog::Open( EAppMsgType::Ok, FText::Format( LOCTEXT("UpdateDoesNotMatch", "The updated image ({0}) does not match the original's size"), FText::FromString( FileName ) ) );
|
|
}
|
|
|
|
bSuccess = true;
|
|
}
|
|
else if (!Font->Textures.IsValidIndex(PageNum))
|
|
{
|
|
FMessageDialog::Open( EAppMsgType::Ok, LOCTEXT("FailedToImportFontPage", "Tried to import an invalid page number."));
|
|
}
|
|
}
|
|
|
|
return bSuccess;
|
|
}
|
|
|
|
void FFontEditor::OnObjectReimported(UObject* InObject)
|
|
{
|
|
// Make sure we are using the object that is being reimported, otherwise a lot of needless work could occur.
|
|
if(Font == InObject)
|
|
{
|
|
Font = Cast<UFont>(InObject);
|
|
|
|
TArray< UObject* > ObjectList;
|
|
ObjectList.Add(InObject);
|
|
FontProperties->SetObjects(ObjectList);
|
|
}
|
|
}
|
|
|
|
bool FFontEditor::RecreateFontObject(const EFontCacheType NewCacheType)
|
|
{
|
|
bool bSuccess = false;
|
|
|
|
UFactory* FontFactoryPtr = nullptr;
|
|
|
|
switch(NewCacheType)
|
|
{
|
|
case EFontCacheType::Offline:
|
|
// UTrueTypeFontFactory will create a new font object using a texture generated from a user-selection font
|
|
FontFactoryPtr = NewObject<UTrueTypeFontFactory>();
|
|
break;
|
|
|
|
case EFontCacheType::Runtime:
|
|
// UFontFactory will create an empty font ready to add new font files to
|
|
FontFactoryPtr = NewObject<UFontFactory>();
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if(FontFactoryPtr && FontFactoryPtr->ConfigureProperties())
|
|
{
|
|
bool OutCanceled = false;
|
|
if (FontFactoryPtr->ImportObject(Font->GetClass(), Font->GetOuter(), *Font->GetName(), RF_Public | RF_Standalone, TEXT(""), nullptr, OutCanceled) != nullptr)
|
|
{
|
|
bSuccess = true;
|
|
}
|
|
}
|
|
|
|
if(bSuccess)
|
|
{
|
|
Font->PostEditChange();
|
|
GEditor->BroadcastObjectReimported(Font);
|
|
}
|
|
|
|
// Let listeners know whether the reimport was successful or not
|
|
FReimportManager::Instance()->OnPostReimport().Broadcast(Font, bSuccess);
|
|
|
|
return bSuccess;
|
|
}
|
|
|
|
bool FFontEditor::GetIsPropertyVisible(const FPropertyAndParent& PropertyAndParent) const
|
|
{
|
|
static const FName CategoryFName = "Category";
|
|
const FString& CategoryValue = PropertyAndParent.Property.GetMetaData(CategoryFName);
|
|
|
|
// We need to hide the properties associated with the category that we're not currently using (either Offline or Runtime)
|
|
const FString CategoryToExclude = (Font->FontCacheType == EFontCacheType::Offline) ? TEXT("RuntimeFont") : TEXT("OfflineFont");
|
|
|
|
// We need to hide the properties associated with the category that we're not currently using (either Offline or Runtime)
|
|
return CategoryValue != CategoryToExclude;
|
|
}
|
|
|
|
bool FFontEditor::ShouldPromptForNewFilesOnReload(const UObject& EditingObject) const
|
|
{
|
|
return false;
|
|
}
|
|
|
|
void FFontEditor::RefreshPreview()
|
|
{
|
|
FontPreviewWidget->RefreshViewport();
|
|
}
|
|
|
|
#undef LOCTEXT_NAMESPACE
|