Files
UnrealEngineUWP/Engine/Source/Editor/UMGEditor/Private/WidgetBlueprintFactory.cpp
iniside c8bb69e713 PR #8650: Allow selecting Abstract Classes as base for UserWidget (Contributed by iniside)
#rb vincent.gauthier

#ROBOMERGE-AUTHOR: vincent.gauthier
#ROBOMERGE-SOURCE: CL 18430882 in //UE5/Release-5.0/... via CL 18435318
#ROBOMERGE-BOT: STARSHIP (Release-Engine-Staging -> Release-Engine-Test) (v897-18405271)

[CL 18435553 by iniside in ue5-release-engine-test branch]
2021-12-10 17:48:04 -05:00

171 lines
6.7 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "WidgetBlueprintFactory.h"
#include "UObject/Interface.h"
#include "Misc/MessageDialog.h"
#include "Blueprint/UserWidget.h"
#include "Blueprint/WidgetBlueprintGeneratedClass.h"
#include "WidgetBlueprint.h"
#include "Kismet2/KismetEditorUtilities.h"
#include "Modules/ModuleManager.h"
#include "Blueprint/WidgetTree.h"
#include "UMGEditorProjectSettings.h"
#include "ClassViewerModule.h"
#include "Kismet2/SClassPickerDialog.h"
#include "ClassViewerFilter.h"
#include "Components/CanvasPanel.h"
#include "Components/HorizontalBox.h"
#include "Components/VerticalBox.h"
#include "Components/GridPanel.h"
#define LOCTEXT_NAMESPACE "UWidgetBlueprintFactory"
/*------------------------------------------------------------------------------
UWidgetBlueprintFactory implementation.
------------------------------------------------------------------------------*/
class FWidgetClassFilter : public IClassViewerFilter
{
public:
/** All children of these classes will be included unless filtered out by another setting. */
TSet <const UClass*> AllowedChildrenOfClasses;
/** Disallowed class flags. */
EClassFlags DisallowedClassFlags;
virtual bool IsClassAllowed(const FClassViewerInitializationOptions& InInitOptions, const UClass* InClass, TSharedRef< FClassViewerFilterFuncs > InFilterFuncs) override
{
return !InClass->HasAnyClassFlags(DisallowedClassFlags)
&& InFilterFuncs->IfInChildOfClassesSet(AllowedChildrenOfClasses, InClass) != EFilterReturn::Failed;
}
virtual bool IsUnloadedClassAllowed(const FClassViewerInitializationOptions& InInitOptions, const TSharedRef< const IUnloadedBlueprintData > InUnloadedClassData, TSharedRef< FClassViewerFilterFuncs > InFilterFuncs) override
{
return !InUnloadedClassData->HasAnyClassFlags(DisallowedClassFlags)
&& InFilterFuncs->IfInChildOfClassesSet(AllowedChildrenOfClasses, InUnloadedClassData) != EFilterReturn::Failed;
}
};
UWidgetBlueprintFactory::UWidgetBlueprintFactory(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{
bCreateNew = true;
bEditAfterNew = true;
SupportedClass = UWidgetBlueprint::StaticClass();
ParentClass = nullptr;
}
bool UWidgetBlueprintFactory::ConfigureProperties()
{
{
FClassViewerModule& ClassViewerModule = FModuleManager::LoadModuleChecked<FClassViewerModule>("ClassViewer");
// Fill in options
FClassViewerInitializationOptions Options;
Options.DisplayMode = EClassViewerDisplayMode::Type::TreeView;
Options.Mode = EClassViewerMode::ClassPicker;
Options.bShowNoneOption = false;
Options.bExpandAllNodes = true;
TSharedPtr<FWidgetClassFilter> Filter = MakeShareable(new FWidgetClassFilter);
Options.ClassFilters.Add(Filter.ToSharedRef());
Options.ExtraPickerCommonClasses.Add(UUserWidget::StaticClass());
Filter->DisallowedClassFlags = CLASS_Deprecated | CLASS_NewerVersionExists;
Filter->AllowedChildrenOfClasses.Add(UUserWidget::StaticClass());
const FText TitleText = LOCTEXT("CreateWidgetBlueprint", "Pick Root Widget for New Widget Blueprint");
UClass* ChosenParentClass = nullptr;
SClassPickerDialog::PickClass(TitleText, Options, ChosenParentClass, UUserWidget::StaticClass());
ParentClass = ChosenParentClass ? ChosenParentClass : UUserWidget::StaticClass();
}
if (GetDefault<UUMGEditorProjectSettings>()->bUseWidgetTemplateSelector)
{
// Load the classviewer module to display a class picker
FClassViewerModule& ClassViewerModule = FModuleManager::LoadModuleChecked<FClassViewerModule>("ClassViewer");
// Fill in options
FClassViewerInitializationOptions Options;
Options.Mode = EClassViewerMode::ClassPicker;
Options.bShowNoneOption = true;
Options.ExtraPickerCommonClasses.Add(UHorizontalBox::StaticClass());
Options.ExtraPickerCommonClasses.Add(UVerticalBox::StaticClass());
Options.ExtraPickerCommonClasses.Add(UGridPanel::StaticClass());
Options.ExtraPickerCommonClasses.Add(UCanvasPanel::StaticClass());
TSharedPtr<FWidgetClassFilter> Filter = MakeShareable(new FWidgetClassFilter);
Options.ClassFilters.Add(Filter.ToSharedRef());
Filter->DisallowedClassFlags = CLASS_Abstract | CLASS_Deprecated | CLASS_NewerVersionExists;
Filter->AllowedChildrenOfClasses.Add(UPanelWidget::StaticClass());
const FText TitleText = LOCTEXT("CreateWidgetBlueprint", "Pick Root Widget for New Widget Blueprint");
return SClassPickerDialog::PickClass(TitleText, Options, static_cast<UClass*&>(RootWidgetClass), UPanelWidget::StaticClass());
}
return true;
}
bool UWidgetBlueprintFactory::ShouldShowInNewMenu() const
{
return true;
}
UObject* UWidgetBlueprintFactory::FactoryCreateNew(UClass* Class, UObject* InParent, FName Name, EObjectFlags Flags, UObject* Context, FFeedbackContext* Warn, FName CallingContext)
{
// Make sure we are trying to factory a Anim Blueprint, then create and init one
check(Class->IsChildOf(UWidgetBlueprint::StaticClass()));
UClass* CurrentParentClass = ParentClass;
if (CurrentParentClass == nullptr)
{
CurrentParentClass = GetDefault <UUMGEditorProjectSettings>()->DefaultWidgetParentClass.LoadSynchronous();
}
// If they selected an interface, force the parent class to be UInterface
if (BlueprintType == BPTYPE_Interface)
{
CurrentParentClass = UInterface::StaticClass();
}
if ( (CurrentParentClass == nullptr) || !FKismetEditorUtilities::CanCreateBlueprintOfClass(CurrentParentClass) || !CurrentParentClass->IsChildOf(UUserWidget::StaticClass()) )
{
FFormatNamedArguments Args;
Args.Add( TEXT("ClassName"), CurrentParentClass ? FText::FromString( CurrentParentClass->GetName() ) : LOCTEXT("Null", "(null)") );
FMessageDialog::Open( EAppMsgType::Ok, FText::Format( LOCTEXT("CannotCreateWidgetBlueprint", "Cannot create a Widget Blueprint based on the class '{ClassName}'."), Args ) );
return nullptr;
}
else
{
if (!GetDefault<UUMGEditorProjectSettings>()->bUseWidgetTemplateSelector)
{
RootWidgetClass = GetDefault<UUMGEditorProjectSettings>()->DefaultRootWidget;
}
UWidgetBlueprint* NewBP = CastChecked<UWidgetBlueprint>(FKismetEditorUtilities::CreateBlueprint(CurrentParentClass, InParent, Name, BlueprintType, UWidgetBlueprint::StaticClass(), UWidgetBlueprintGeneratedClass::StaticClass(), CallingContext));
// Create the desired root widget specified by the project
if ( NewBP->WidgetTree->RootWidget == nullptr )
{
if (TSubclassOf<UPanelWidget> RootWidgetPanel = RootWidgetClass)
{
UWidget* Root = NewBP->WidgetTree->ConstructWidget<UWidget>(RootWidgetPanel);
NewBP->WidgetTree->RootWidget = Root;
}
}
return NewBP;
}
}
UObject* UWidgetBlueprintFactory::FactoryCreateNew(UClass* Class, UObject* InParent, FName Name, EObjectFlags Flags, UObject* Context, FFeedbackContext* Warn)
{
return FactoryCreateNew(Class, InParent, Name, Flags, Context, Warn, NAME_None);
}
#undef LOCTEXT_NAMESPACE