Adding Components Support To UMG Widgets
Components in Unreal are exceptionally powerful. They allow developers to roll functionality into a single piece of code without it polluting anything else. If we put all code pertaining to an exploding barrel in ExplodingBarrel.h, we'd end up with a colossal monolith of a class. On top of that, we'd have to duplicate the explosion code whenever we wanted something else to explode. One thing that UMG is lacking is the ability to have components sit on widgets. Doesn’t seem too bad on first blush, but if we start adding say "Drag and Drop" functionality to parts of our UI, we're just a stones throw away from that giant monolithic class that would otherwise make our skin crawl if it was anything other that UI. Here's my proposed solution to this lack of architecture - the WidgetSubComponent. A base class component to mimic the ActorComponent architecture, with all the fancy bells and whistles we'd expect in terms of editor hookups. We're also gunning for full blueprint support here - UI isnt something code should exclusively drive. This is a bit of a beastly change, so lets quickly take a look at what we're actually making before we bite the bullet and make it -
EXAMPLE

#pragma once

#include <Runtime/UMG/Public/Blueprint/UserWidget.h>
    
#include "TestWidget.generated.h"
    
UCLASS()
class UTestWidget : public UUserWidget
{
    GENERATED_BODY()
    
    UTestWidget(const FObjectInitializer& InObjectInitialiser)
        : Super(InObjectInitialiser)
    {};
    
    UPROPERTY(meta=(BindComponent))
    class UWidgetSubComponent* TestComp;
};
We'll be adding a new meta specifier called BindComponent to mirror the BindAnimation and BindWidget specifiers. Once NativeConstruct has been called, the Widget will pull the component from the Components array and pop it into the correctly named member variable in native. To add the component to the widget, all we have to do is -
AIControllerSetup
Of course we're free to add any other member variables to TestComponent - they'll all show up here. With this in place, we're free to chunk up code that handles functionality as we would otherwise do in gameplay code. As far as im concerned, there's absolutely no reason why Drag and Drop functionality should sit besides visual code. Its messy and we can do better!
New WidgetSubComponent Class
We first need to define a new base class; something that's going to act as our ActorComponent proxy. Primarily, it'll contain our Binding property for the WidgetCompiler to latch on to, but also a lot of the convivence functions we'd expect in the base engine.
NEW FILE - Runtime\UMG\Public\WidgetSubComponent\WidgetSubComponent.h

#pragma once

#include <Runtime/CoreUObject/Public/UObject/Object.h>

//start @AirEngine Class added to operate as a worker component.  UMG tends to bloat, especially master ones, so adding a new UWidgetSubComponent 
//class allows for effective and efficient compartmentalization

#include "WidgetSubComponent.generated.h"

class UUserWidget;

UCLASS(MinimalAPI, EditInlineNew, Blueprintable, BlueprintType, meta = (ShortTooltip = "A SubWidgetComponent is a reusable component that can be added to any UUserWidget."))
class UWidgetSubComponent : public UObject
{
	GENERATED_BODY()

public:

	UWidgetSubComponent(const FObjectInitializer& InObjectInitialiser);

	UFUNCTION(BlueprintNativeEvent, meta=(DisplayName="Native Construct"))
	void ReceiveNativeConstruct();
	void ReceiveNativeConstruct_Implementation() {};

	UFUNCTION(BlueprintNativeEvent, meta=(DisplayName="Native Destruct"))
	void ReceiveNativeDestruct();
	void ReceiveNativeDestruct_Implementation() {};
	
	UFUNCTION(BlueprintNativeEvent, meta=(DisplayName="Native Tick"))
	void ReceiveNativeTick(const float InDeltaTime);
	void ReceiveNativeTick_Implementation(const float InDeltaTime) {};

	virtual void NativeConstruct();
	virtual void NativeDestruct();
	virtual void NativeTick(const float InDeltaTime);

	TWeakObjectPtr<UUserWidget> GetWidget() const;
	UMG_API const FName* GetBindingName() const;

protected:

	UPROPERTY(EditAnywhere, Category = "Binding")
	FName BindingName;

	UPROPERTY(BlueprintReadOnly, Category = "WidgetSubComponent")
	UUserWidget* OwningWidget;

	UPROPERTY(BlueprintReadOnly, Category = "WidgetSubComponent")
	APlayerController* LocalController;
};
NEW FILE - Runtime\UMG\Private\WidgetSubComponent\WidgetSubComponent.cpp

#pragma once

#include "Runtime/UMG/Public/WidgetSubComponent/WidgetSubComponent.h"

#include "Runtime/UMG/Public/Blueprint/UserWidget.h"

UWidgetSubComponent::UWidgetSubComponent(const FObjectInitializer& InObjectInitialiser)
	: Super(InObjectInitialiser)
{}

void UWidgetSubComponent::NativeConstruct()
{
	if(UUserWidget* OuterWidget = CastChecked<UUserWidget>(GetOuter()))
	{
		OwningWidget = OuterWidget;
	}

	if (UWorld* World = GetWorld())
	{
		LocalController = World->GetFirstPlayerController();
	}

	ReceiveNativeConstruct();
}

void UWidgetSubComponent::NativeDestruct()
{
	ReceiveNativeDestruct();
}

void UWidgetSubComponent::NativeTick(const float InDeltaTime)
{
	ReceiveNativeTick(InDeltaTime);
}

TWeakObjectPtr<UUserWidget> UWidgetSubComponent::GetWidget() const
{
	return OwningWidget;
}

const FName* UWidgetSubComponent::GetBindingName() const
{
	return &BindingName;
}
For the most part, this is boilerplate. An object with spin up, spin down and tick machinery. Nothing too fancy, nor ground breaking. All this rubbish is virtual, so we're totally free to inherit and extend as much as we'd like. Now comes the tricky part - getting the BlueprintWidget to acknowledge they exist in a way that isnt totally insane.
Adding SubComponent Support to UUserWidgets - the tricky bit
Firstly, lets add an array of these bad boys to the UUserWidget base class - this is where we essentially tell each widget what components it owns. There's actually an array on Actor called OwnedComponents that serves a similar purpose.
ADDITION - UserWidget.h - Adding OwnedComponents Array

UPROPERTY(EditAnywhere, Instanced, Category = "Components", meta = (DisplayName = "Components", Tooltip = "What components should be added to this widget on native construct"))
TArray<class UWidgetSubComponent*> OwnedComponents;
Now we've got an array of objects to mess with, lets deal with actually integrating them into the UUserWidget Framework. For the most part, this routing the spin up, spin down and tick calls, but it also deals with populating any native members the widget might have, much like we'd expect BindAnimation and BindWidget members to be populated.
CHANGE - UserWidget.cpp - Include relevant header

//start @AirEngine Add support for WidgetSubComponent
#include "Runtime/UMG/Public/WidgetSubComponent/WidgetSubComponent.h"
//end @AirEngine
CHANGE - UserWidget.cpp - Route NativeDestruct

void UUserWidget::NativeDestruct()
{
    StopListeningForAllInputActions();
    
    //start @AirEngine Add support for WidgetSubComponents
    for(UWidgetSubComponent* Component : OwnedComponents)
    {
        Component->NativeDestruct();	
    }
    //end @AirEngine
    
    Destruct();
}
CHANGE - UserWidget.cpp - Route NativeTick

void UUserWidget::NativeTick(const FGeometry& MyGeometry, float InDeltaTime)
{
    //Existing tick functionality
    
    //start @AirEngine Add support for Widget SubComponents
    for(UWidgetSubComponent* SubComponent : OwnedComponents)
    {
        SubComponent->NativeTick(InDeltaTime);
    }
    //end @AirEngine
}
This if course comes with the concession that any deeper engine optimisations that would otherwise turn off a widgets tick will also apply to our component. Further changes would have to be made to keep a component's tick plodding along whilst the outer widget's has been turned off, although an FTimerHandle bunged into the WorldTimerManager could probably give you a halfway decent middleground. Adding NativeConstruct is a bit more of a handful. It makes sense to piggy back off of the existing one in UUserWidget, sure, but the OwnedComponents at this point are technically the ones from the WidgetBlueprint's CDO. Lets take whatever the Widget reckons is right and sort of formalise them by spinning up our own versions. First we'll need some framework in the header to make our lives a bit easier -
ADDITION - UserWidget.h - Route NativeTick and add Component Fixup support

//Templates cant be in .cpp, so this will have to live in the header
template<typename TProperty>
TProperty* GetPropertyByName(const FName& InName)
{
	if (UClass* Class = GetClass())
	{
		if(FProperty* Property = GetClass()->FindPropertyByName(InName))
		{
			return CastField<TProperty>(Property);
		}
	}

	return nullptr;
};

void FixupSubComponents();
ADDITION - UserWidget.cpp - Route NativeTick and add Component Fixup support

//start @AirEngine - add support for WidgetSubComponents
void UUserWidget::FixupSubComponents()
{
    TArray<UWidgetSubComponent*> DuplicatedComponents;
    
    for (UWidgetSubComponent* Component : OwnedComponents)
    {
        if (UWidgetSubComponent* DuplicatedComp = DuplicateObject<UWidgetSubComponent>(Component, this, Component->GetFName()))
        {
            //If we can bind this, bind it.
            if (FObjectPropertyBase* TargetProp = GetPropertyByName<FObjectPropertyBase>(*Component->GetBindingName()))
            {
                void* ValuePtr = TargetProp->ContainerPtrToValuePtr<void>(this);
                TargetProp->SetObjectPropertyValue(ValuePtr, DuplicatedComp);
            }

            DuplicatedComponents.AddUnique(DuplicatedComp);
        }

        Component->NativeConstruct();
    }

    //Replaced our CDO components with newly initialised ones
    OwnedComponents = DuplicatedComponents;
}
//end @AirEngine
CHANGE - UserWidget.cpp - Route NativeTick and add Component Fixup support

void UUserWidget::NativeConstruct()
{
	//start @AirEngine Add support for WidgetSubComponents
	FixupSubComponents();
	//end @AirEngine

	Construct();
	UpdateCanTick();
}
This above block will parse the current class, find any members that match binding names, and populate that member with the appropriate element in the OwnedComponents array. IMPORTANT! We're gunning for full blueprint support here. As such, we should account for widgets based entirely on UUserWidget with no BindComponent functionality. Basically, components can exist on a widget with no binding in native - chilling in the OwnedComponents array should be enough.
WidgetBlueprint Compilation Support - Maybe an even trickier bit
Now we've got a components being added to the Widget, we need to add parity in regards to how the UMG Editor deals with missing bindings. If we fail to bind to a Widget through BindWidget, or indeed an Animation through BindWidgetAnim, the compiler will kick up a fuss - error messages, failure to load current widget state at runtime, it’s a real mess. This addition looks messier than it actually is, I promise - the bulk of the work takes place in the WidgetBlueprintCompiler. Firstly, we need to actually add the definition for the "BindComponent" metadata.
ADDITION - Widget.h, underneath the entry for EntryInterface, roughly line 83.

//start @AirEngine Add WidgetSubComponent support
// [PropertyMetadata] This property requires a WidgetSubComponent to be bound to it in in the designer.  Allows for easy native access to designer defined component functionality
// UPROPERTY(meta=(BindComponent))
BindComponent,
This addition essentially flags to the compiler that BindComponent is indeed a legal meta specifier within UWidget, and we also get the opportunity to provide some flavour text, giving the developer a bit of a hint as to what this specifier does. Next, lets deal with predicting if we even need to make any bindings for this current class -
ADDITION - WidgetBlueprintCompiler.h - Add array to hold properties we anticipate binding to

//start @AirEngine Add support for WidgetSubComponent
TArray<class FObjectPropertyBase*> WidgetComponentArray;
//end @AirEngine
CHANGE - WidgetBlueprintCompiler.cpp - Add block at the bottom of FWidgetBlueprintCompilerContext::CreateClassVariablesFromBlueprint

//start @AirEngine Add support for WidgetSubComponent
for (TFObjectPropertyBase<UWidgetSubComponent*>* SubComponentProperty : TFieldRange<TFObjectPropertyBase<UWidgetSubComponent*>>(ParentClass))
{
    if (FWidgetBlueprintEditorUtils::IsBindComponentProperty(*SubComponentProperty))
    {
        WidgetComponentArray.Add(SubComponentProperty);
    }
}
//end @AirEngine
We'll also need to implement that static IsBindComponentProperty function.
ADDITION - WidgetBlueprintEditorUtils.h

//start @AirEngine Add support for WidgetSubComponents
static bool IsBindComponentProperty(FProperty& InProperty);
//end @AirEngine
ADDITION - WidgetBlueprintEditorUtils.cpp

//start @AirEngine Add support for WidgetSubComponents
bool FWidgetBlueprintEditorUtils::IsBindComponentProperty(FProperty& InProperty)
{
    return InProperty.HasMetaData("BindComponent");
}
//end @AirEngine
Nothing too fancy here - we can quite literally poll to see if the FProperty has the metadata BindComponent on it. If it is, we'll consider it liable for a binding. CreateClassVariablesFromBlueprint is actually called as soon as we hit Compile in the Widget Blueprint. As such, we should have an array of FObjectPropertyBase* representing properties that need binding in the next phase of compilation very early on. If the array is empty, we can assume the widget doesnt actually require any components to be bound. However, if we do have properties that need a hookup, we can proceed to validate the bindings. Inside the FinishCompilingClass function, we need to add the following block -
CHANGE - Inside FWidgetBlueprintCompilerContext::FinishCompilingClass

if (bIsSkeletonOnly)
{
    //First pass - verify all components have been created at edit time
    if (WidgetComponentArray.Num() > 0)
    {
        if (UWidgetBlueprintGeneratedClass* BPGC = Cast<UWidgetBlueprintGeneratedClass>(WidgetBP->GeneratedClass))
        {
            if (UUserWidget* DefaultWidget = BPGC->GetDefaultObject<UUserWidget>())
            {
                const TArray<UWidgetSubComponent*> Components = DefaultWidget->OwnedComponents;

                for (uint8 i = 0; i < Components.Num(); ++i)
                {
                    if (Components[i] != nullptr)
                    {
                        const FString SubcomponentName = Components[i]->GetClass()->GetName();
                        if (SubcomponentName.Contains(TEXT("REINST_")))
                        {
                            DefaultWidget->OwnedComponents[i] = &ReinstanceComponent(Components[i]);
                        }
                    }
                }

                for (const FObjectPropertyBase* WidgetComponent : WidgetComponentArray)
                {
                    const FName ExpectedName = WidgetComponent->GetFName();
                    const FText RequiredComponentNotBoundError = LOCTEXT("RequiredComponentNotBound", "A required component binding \"{0}\" (\"{1}\") was not found.");
                    const FText RequiredComponentBoundLog = LOCTEXT("RequiredComponentBound", "\"{0}\" was successfully bound");

                    const int8 IndexOfMatchingProperty = Components.IndexOfByPredicate([&ExpectedName](UWidgetSubComponent* SubComp) ->bool
                    {
                        if (SubComp != nullptr)
                        {
                            return *SubComp->GetBindingName() == ExpectedName;
                        }

                        return false;
                    });

                    if (IndexOfMatchingProperty == INDEX_NONE)
                    {
                        const FText ErrorLog = FText::Format
                        (RequiredComponentNotBoundError,
                            FText::FromName(ExpectedName),
                            FText::FromName(WidgetComponent->PropertyClass->GetFName()));
                        MessageLog.Error(*ErrorLog.ToString());
                    }
                    else
                    {
                        MessageLog.Note(*FText::Format(RequiredComponentBoundLog, FText::FromName(ExpectedName)).ToString());
                    }
                }
            }
        }
    }
}
What we're doing here is essentially predicting any bindings that'll be made as soon as we call NativeConstruct. If we Fail to bind, belt a whole load of errors into the output log, prompting the designer to fulfull the contract the whole BindX architecture imposes. If we fail to bind here, we'll be greeted with this lovely message -
AIControllerSetup
In ths case, we've got a UserWidget expecting a WidgetSubComponent member to be populated from the Design layer, of name "TestComp". Fail both criteria, get hit with a compile hammer. IMPORTANT! Because we're building out a full feature here, we need to be cogniscant of REINST_ objects sneaking their way in. The TLDR here is - if we have a Blueprint authored component present as a bound component, it'll be made stale as soon as the source blueprint gets recompiled. The stale version will get prefixed with REINST_ and get nulled out on save. That's a real nightmare in terms of scalabilty, and we'll need to fix it. You'll of noticed we've made a call to a "ReinstanceComponent" function in the above mess of code; lets implement that so we can sleep at night.
ADDITION - FWidgetBlueprintCompilerContext::ReinstanceComponent

//start @AirEngine Add support for WidgetSubComponent
UWidgetSubComponent& ReinstanceComponent(UWidgetSubComponent* InStaleComponent);
TArray<class FObjectPropertyBase*> WidgetComponentArray;
//end @AirEngine
ADDITION - FWidgetBlueprintCompilerContext::ReinstanceComponent

UWidgetSubComponent& FWidgetBlueprintCompilerContext::ReinstanceComponent(UWidgetSubComponent* InStaleComponent)
{
    MessageLog.Note(*FString::Printf(TEXT("%s is stale - reinstancing"), *InStaleComponent->GetName()));
    
    UWidgetSubComponent* ReinstancedComponent = NewObject<UWidgetSubComponent>(InStaleComponent->GetOuter(), InStaleComponent->GetClass()->GetAuthoritativeClass());
    UEngine::CopyPropertiesForUnrelatedObjects(InStaleComponent, ReinstancedComponent);
  
    return *ReinstancedComponent;
}
//end @AirEngine
Quite simply, we detect that one of our components has been made stale, so we create a new, non-stale version, and copy over what we can from the previously stale version. This new component is not stale, and not out of date, so we dont have to worry about having it nulled out. Our final final final bit of logic work is to do a single line of cleanup.
CHANGE - Empty our runtime array in FWidgetBlueprintCompilerContext::OnPostCDOCompiled, under WidgetAnimToMemberVariableMap.Empty()

WidgetComponentArray.Empty();
Icons, Styling and Visuals
We're on the home stretch! We've got the actual logic in place, so now we need to add a bunch of Editor facing changes to basically cement WidgetSubComponents as an actually viable Editor feature.
AIControllerSetup
I've mocked up an icon for the WidgetSubComponent - please feel free to yoink! Upscaling hasnt been kind here, but Unreal really only works with icons 16px and 64px square, at least in Slate, so dont sweat it, it'll look primo in-engine. Lets start hooking it up. Firstly, lets list our new WidgetSubComponent class as a "Default Class". The Engine/Content/Editor/Slate/Icons/AssetIcons/ directory contains all manner of Icons used to build out the Engine's slate style - for this change, we'll need to add a couple new icons in here, that being the WidgetSubComponent_16x.png and WidgetSubComponent_64x.png. Once we've got our icon added to the directory, we'll need to flag to the engine that we do indeed have an icon to source - we do that by ammending the SlateEditorStyle.cpp file as such -
ADDITION - Engine\Source\Editor\EditorStyle\Private\SlateEditorStyle.cpp, under TEXT("FoliageType_Actor") in FSlateEditorStyle::FStyle::SetupClassIconsAndThumbnails()

TEXT("WidgetSubComponent")
Pretty simple - we just flag to the engine "hey, if you come across called WidgetSubComponent, i've got an icon for it in the AssetIcons directory". Whenever a child of SubWidgetComponent needs an icon in editor, it's now going to use our new icon.
Factories and Content Browser Functionality
The last thing we need to do is make sure we have all of the Content browser functionalty that's we'd expect of a native class in Unreal - you know what that means. It means object factories. Lets get the big chunky guys out the way first. I wont go too in depth, but Cairan Steverink has an excellent series of posts that talk through the rough outlines. Firstly, lets start with our Editor Module additions.
NEW FILE - Engine\Source\Editor\UMGEditor\Public\WidgetSubComponent\WidgetSubComponentAssetFactory.h

#pragma once
//start @AirEngine - Add support for WidgetSubComponents

#include 

#include "WidgetSubComponentAssetFactory.generated.h"

UCLASS()
class UMGEDITOR_API UWidgetSubComponentAssetFactory : public UFactory 
{
    GENERATED_BODY()

public:

    UWidgetSubComponentAssetFactory(const FObjectInitializer& InObjectInitialiser);

    //UFactory
    virtual UObject* FactoryCreateNew(UClass* InClass, UObject* InParent, FName InName, EObjectFlags Flags, UObject* Context, FFeedbackContext* Warn) override;
    virtual bool ShouldShowInNewMenu() const override;
    virtual uint32 GetMenuCategories() const override;
    virtual FText GetDisplayName() const override;
    //~UFactory
};
NEW FILE - Engine\Source\Editor\UMGEditor\Private\WidgetSubComponent\WidgetSubComponentAssetActions.cpp

#include "Editor/UMGEditor/Public/WidgetSubComponent/WidgetSubComponentAssetFactory.h"
#include <Developer/AssetTools/Public/AssetTypeCategories.h>
#include <Runtime/UMG/Public/WidgetSubComponent/WidgetSubComponent.h>
#include "Kismet2/KismetEditorUtilities.h"

UWidgetSubComponentAssetFactory::UWidgetSubComponentAssetFactory(const FObjectInitializer& InObjectInitialiser)
    : Super(InObjectInitialiser)
{
    SupportedClass = UWidgetSubComponent::StaticClass();
    bCreateNew = true;
    bEditAfterNew = true;
}

UObject* UWidgetSubComponentAssetFactory::FactoryCreateNew(UClass* InClass, UObject* InParent, FName InName, EObjectFlags Flags, UObject* Context, FFeedbackContext* Warn)
{
    return FKismetEditorUtilities::CreateBlueprint(InClass, InParent, InName, EBlueprintType::BPTYPE_Normal, UBlueprint::StaticClass(), UBlueprintGeneratedClass::StaticClass());
}

bool UWidgetSubComponentAssetFactory::ShouldShowInNewMenu() const
{
    return true;
}

uint32 UWidgetSubComponentAssetFactory::GetMenuCategories() const
{
    return EAssetTypeCategories::UI;
}

FText UWidgetSubComponentAssetFactory::GetDisplayName() const
{
    return NSLOCTEXT("WidgetSubComponentFactory", "Widget SubComponent", "Widget SubComponent");
}
From here, we can define some actions about the class -
NEW FILE - Engine\Source\Editor\UMGEditor\Public\WidgetSubComponent\WidgetSubComponentAssetActions.h

#pragma once
//start @AirEngine Add support for WidgetSubComponents

#include "CoreMinimal.h"
#include "Toolkits/IToolkitHost.h"
#include "AssetTypeActions_Base.h"

struct FAssetData;

//TODO Use base class FAssetTypeActions_Blueprint later
class FWidgetSubComponentAssetActions : public FAssetTypeActions_Base
{
public:

    FWidgetSubComponentAssetActions();

    //IAssetTypeActions Implementation
    virtual FText GetName() const override;
    virtual FColor GetTypeColor() const override;
    virtual uint32 GetCategories() override;
    virtual bool CanLocalize() const override;
    virtual UClass* GetSupportedClass() const override;
    //~IAssetTypeActions Implementation
};
NEW FILE - Engine\Source\Editor\UMGEditor\Private\WidgetSubComponent\WidgetSubComponentAssetActions.cpp

#include "Editor/UMGEditor/Public/WidgetSubComponent/WidgetSubComponentAssetActions.h"
#include <Runtime/UMG/Public/WidgetSubComponent/WidgetSubComponent.h>

FWidgetSubComponentAssetActions::FWidgetSubComponentAssetActions()
{

}

FText FWidgetSubComponentAssetActions::GetName() const
{
    return NSLOCTEXT("AssetTypeActions", "WidgetSubComponentAssetActions", "WidgetSubComponent");
}

FColor FWidgetSubComponentAssetActions::GetTypeColor() const
{
    return FColor(44.f, 89.f, 180.f);
}

uint32 FWidgetSubComponentAssetActions::GetCategories()
{
    return EAssetTypeCategories::UI;
}

bool FWidgetSubComponentAssetActions::CanLocalize() const
{
    return false;
}

UClass* FWidgetSubComponentAssetActions::GetSupportedClass() const
{
    return UWidgetSubComponent::StaticClass();
}
Finally, we need to actually register this set of actions. We already register actions for the BlueprintWidget class inside the StartupModule function in UMGEditorModule.cpp, so lets just take the action registration for the WidgetComponent in there too -
ADDITION - below RegisterAssetTypeAction(AssetTools, MakeShareable(new FAssetTypeActions_WidgetBlueprint())); in UMGEditorModule.cpp

RegisterAssetTypeAction(AssetTools, MakeShareable(new FWidgetSubComponentAssetActions()));
With both the factories and actions in place, as well as the Styling, we should be able to create our new asset type directly in the content browser no problemo -
CreateThroughContextMenu
Finishing Touches
There's a few final touches i'd like to integrate to make this feature feel a bit more "native". First things first, lets get this component added to the "Common Blueprint" dialog screen. We have ActorComponent in there, and for some reason we have SceneComponent; lets spread the love and learn a little about the engine at the same time eh. Firstly, we'll want to make sure the Class is considered a Default Class. This is easy enough with the following change -
ADDITION - Added to the Class Picker Dialog block inside BaseEditor.ini

+NewAssetDefaultClasses=(ClassName="/Script/UMG.WidgetSubComponent", AssetClass="/Script/Engine.Blueprint")
We also want to give this box a little bit of a size increase; Widget SubComponent is a bit longer than this box anticipated, so lets change the slate to make the box a squidge bigger -
CHANGE - Line 88 Engine/Source/Editor/UnrealEd/Private/SClassPickerDialog.cpp

.WidthOverride(600.0f)
Literally an extra 20 pixels added to the width of the default class box. Minor I know, but a good exercise in tracking down how Slate is built.
CreateThroughContextMenu
Finally, lets expose out those Blueprint functions inside SubWidgetComponent to let developers know what tools they've got to play with by default.
ADDITION - Engine\Config\BaseEditorPerProjectUserSettings.ini, inside [DefaultEventNodes] block

+Node=(TargetClass=WidgetSubComponent TargetEvent="ReceiveNativeConstruct")
+Node=(TargetClass=WidgetSubComponent TargetEvent="ReceiveNativeDestruct")
+Node=(TargetClass=WidgetSubComponent TargetEvent="ReceiveNativeTick")
CreateThroughContextMenu
This is a bit of a monster I know, but I really think it opens up a miles more approachable UMG pipeline to engineers in it for the long run. As always, any questions please feel free to reach out on Twitter.