Files
UnrealEngine/Engine/Source/Runtime/UMG/Private/Components/Widget.cpp
2025-05-18 13:04:45 +08:00

2062 lines
54 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "Components/Widget.h"
#include "Misc/ConfigCacheIni.h"
#include "Misc/UObjectToken.h"
#include "CoreGlobals.h"
#include "Widgets/SNullWidget.h"
#include "Types/NavigationMetaData.h"
#include "Widgets/IToolTip.h"
#include "Widgets/DeclarativeSyntaxSupport.h"
#include "Widgets/SOverlay.h"
#include "UObject/ObjectSaveContext.h"
#include "UObject/UObjectHash.h"
#include "UObject/UObjectIterator.h"
#include "UObject/Package.h"
#include "Engine/LocalPlayer.h"
#include "Engine/UserInterfaceSettings.h"
#include "Framework/Application/SlateApplication.h"
#include "Widgets/Layout/SBorder.h"
#include "Widgets/Layout/SSpacer.h"
#include "Widgets/SToolTip.h"
#include "Binding/PropertyBinding.h"
#include "Binding/States/WidgetStateBitfield.h"
#include "Binding/States/WidgetStateSettings.h"
#include "Binding/States/WidgetStateRegistration.h"
#include "Binding/WidgetFieldNotificationExtension.h"
#include "Logging/MessageLog.h"
#include "Blueprint/GameViewportSubsystem.h"
#include "Blueprint/UserWidget.h"
#include "Blueprint/UserWidgetBlueprint.h"
#include "Blueprint/WidgetBlueprintGeneratedClass.h"
#include "Slate/SObjectWidget.h"
#include "Blueprint/WidgetTree.h"
#include "UMGStyle.h"
#include "Types/ReflectionMetadata.h"
#include "Trace/SlateMemoryTags.h"
#include "Serialization/PropertyLocalizationDataGathering.h"
#include "Components/NamedSlotInterface.h"
#include "ProfilingDebugging/AssetMetadataTrace.h"
#include "HAL/LowLevelMemStats.h"
#include "Extensions/UIComponentContainer.h"
#include "Extensions/UIComponent.h"
#include "Extensions/UIComponentUserWidgetExtension.h"
#include "Types/InvisibleToWidgetReflectorMetaData.h"
#include UE_INLINE_GENERATED_CPP_BY_NAME(Widget)
#define LOCTEXT_NAMESPACE "UMG"
DECLARE_DWORD_ACCUMULATOR_STAT(TEXT("Total Created UWidgets"), STAT_SlateUTotalWidgets, STATGROUP_SlateMemory);
/**
* Interface for tool tips.
*/
class FDelegateToolTip : public IToolTip
{
public:
/**
* Gets the widget that this tool tip represents.
*
* @return The tool tip widget.
*/
virtual TSharedRef<class SWidget> AsWidget() override
{
return GetContentWidget();
}
/**
* Gets the tool tip's content widget.
*
* @return The content widget.
*/
virtual TSharedRef<SWidget> GetContentWidget() override
{
if ( CachedToolTip.IsValid() )
{
return CachedToolTip.ToSharedRef();
}
UWidget* Widget = ToolTipWidgetDelegate.Execute();
if ( Widget )
{
CachedToolTip = Widget->TakeWidget();
return CachedToolTip.ToSharedRef();
}
return SNullWidget::NullWidget;
}
/**
* Sets the tool tip's content widget.
*
* @param InContentWidget The new content widget to set.
*/
virtual void SetContentWidget(const TSharedRef<SWidget>& InContentWidget) override
{
CachedToolTip = InContentWidget;
}
/**
* Checks whether this tool tip has no content to display right now.
*
* @return true if the tool tip has no content to display, false otherwise.
*/
virtual bool IsEmpty() const override
{
return !ToolTipWidgetDelegate.IsBound();
}
/**
* Checks whether this tool tip can be made interactive by the user (by holding Ctrl).
*
* @return true if it is an interactive tool tip, false otherwise.
*/
virtual bool IsInteractive() const override
{
return false;
}
virtual void OnClosed() override
{
//TODO Notify interface implementing widget of closure
CachedToolTip.Reset();
}
virtual void OnOpening() override
{
//TODO Notify interface implementing widget of opening
}
public:
UWidget::FGetWidget ToolTipWidgetDelegate;
private:
TSharedPtr<SWidget> CachedToolTip;
};
#if WITH_EDITORONLY_DATA
namespace
{
void GatherWidgetForLocalization(const UObject* const Object, FPropertyLocalizationDataGatherer& PropertyLocalizationDataGatherer, const EPropertyLocalizationGathererTextFlags GatherTextFlags)
{
const UWidget* const Widget = CastChecked<UWidget>(Object);
EPropertyLocalizationGathererTextFlags WidgetGatherTextFlags = GatherTextFlags;
// If we've instanced this widget from another asset, then we only want to process the widget itself (to process any overrides against the archetype), but skip all of its children
if (UObject* WidgetGenerator = Widget->WidgetGeneratedBy.Get())
{
if (WidgetGenerator->GetOutermost() != Widget->GetOutermost())
{
WidgetGatherTextFlags |= EPropertyLocalizationGathererTextFlags::SkipSubObjects;
}
}
PropertyLocalizationDataGatherer.GatherLocalizationDataFromObject(Widget, WidgetGatherTextFlags);
}
}
#endif
/////////////////////////////////////////////////////
// UWidget
TArray<TSubclassOf<UPropertyBinding>> UWidget::BinderClasses;
/////////////////////////////////////////////////////
void UWidget::FFieldNotificationClassDescriptor::ForEachField(const UClass* Class, TFunctionRef<bool(::UE::FieldNotification::FFieldId FielId)> Callback) const
{
for (int32 Index = 0; Index < Max_IndexOf_; ++Index)
{
if (!Callback(*AllFields[Index]))
{
return;
}
}
if (const UBlueprintGeneratedClass* BPClass = Cast<const UBlueprintGeneratedClass>(Class))
{
BPClass->ForEachFieldNotify(Callback, true);
}
}
UE_FIELD_NOTIFICATION_IMPLEMENT_CLASS_DESCRIPTOR_ThreeFields(UWidget, ToolTipText, Visibility, bIsEnabled);
UWidget::UWidget(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{
PRAGMA_DISABLE_DEPRECATION_WARNINGS
bIsEnabled = true;
bIsVariable = true;
bIsManagedByGameViewportSubsystem = false;
#if WITH_EDITOR
DesignerFlags = static_cast<uint8>(EWidgetDesignFlags::None);
#endif
Visibility = ESlateVisibility::Visible;
RenderOpacity = 1.0f;
RenderTransformPivot = FVector2D(0.5f, 0.5f);
Cursor = EMouseCursor::Default;
PixelSnapping = EWidgetPixelSnapping::Inherit;
#if WITH_EDITORONLY_DATA
bOverrideAccessibleDefaults = false;
AccessibleBehavior = ESlateAccessibleBehavior::NotAccessible;
AccessibleSummaryBehavior = ESlateAccessibleBehavior::Auto;
bCanChildrenBeAccessible = true;
#endif
AccessibleWidgetData = nullptr;
bShouldBroadcastState = true;
bWidgetStateInitialized = false;
bWrappedByComponent = false;
PRAGMA_ENABLE_DEPRECATION_WARNINGS
#if WITH_EDITORONLY_DATA
{ static const FAutoRegisterLocalizationDataGatheringCallback AutomaticRegistrationOfLocalizationGatherer(UWidget::StaticClass(), &GatherWidgetForLocalization); }
#endif
INC_DWORD_STAT(STAT_SlateUTotalWidgets);
}
PRAGMA_DISABLE_DEPRECATION_WARNINGS
const FWidgetTransform& UWidget::GetRenderTransform() const
{
return RenderTransform;
}
void UWidget::SetRenderTransform(FWidgetTransform Transform)
{
RenderTransform = Transform;
UpdateRenderTransform();
}
void UWidget::SetRenderScale(FVector2D Scale)
{
RenderTransform.Scale = Scale;
UpdateRenderTransform();
}
void UWidget::SetRenderShear(FVector2D Shear)
{
RenderTransform.Shear = Shear;
UpdateRenderTransform();
}
void UWidget::SetRenderTransformAngle(float Angle)
{
RenderTransform.Angle = Angle;
UpdateRenderTransform();
}
float UWidget::GetRenderTransformAngle() const
{
return RenderTransform.Angle;
}
void UWidget::SetRenderTranslation(FVector2D Translation)
{
RenderTransform.Translation = Translation;
UpdateRenderTransform();
}
void UWidget::UpdateRenderTransform()
{
TSharedPtr<SWidget> SafeWidget = GetCachedWidget();
if (SafeWidget.IsValid())
{
if (RenderTransform.IsIdentity())
{
SafeWidget->SetRenderTransform(TOptional<FSlateRenderTransform>());
}
else
{
SafeWidget->SetRenderTransform(RenderTransform.ToSlateRenderTransform());
}
}
}
FVector2D UWidget::GetRenderTransformPivot() const
{
return RenderTransformPivot;
}
void UWidget::SetRenderTransformPivot(FVector2D Pivot)
{
RenderTransformPivot = Pivot;
TSharedPtr<SWidget> SafeWidget = GetCachedWidget();
if (SafeWidget.IsValid())
{
SafeWidget->SetRenderTransformPivot(Pivot);
}
}
EFlowDirectionPreference UWidget::GetFlowDirectionPreference() const
{
return FlowDirectionPreference;
}
void UWidget::SetFlowDirectionPreference(EFlowDirectionPreference FlowDirection)
{
FlowDirectionPreference = FlowDirection;
if (TSharedPtr<SWidget> SafeWidget = GetCachedWidget())
{
SafeWidget->SetFlowDirectionPreference(FlowDirectionPreference);
}
}
bool UWidget::GetIsEnabled() const
{
TSharedPtr<SWidget> SafeWidget = GetCachedWidget();
return SafeWidget.IsValid() ? SafeWidget->IsEnabled() : bIsEnabled;
}
void UWidget::SetIsEnabled(bool bInIsEnabled)
{
bool bValueChanged = false;
if (bIsEnabled != bInIsEnabled)
{
bIsEnabled = bInIsEnabled;
bValueChanged = true;
}
TSharedPtr<SWidget> SafeWidget = GetCachedWidget();
if (SafeWidget.IsValid())
{
SafeWidget->SetEnabled(bInIsEnabled);
}
if (bValueChanged)
{
BroadcastFieldValueChanged(FFieldNotificationClassDescriptor::bIsEnabled);
// Note: State is disabled, so we broadcast !bIsEnabled
BroadcastBinaryPostStateChange(UWidgetDisabledStateRegistration::Bit, !bIsEnabled);
}
}
bool UWidget::IsInViewport() const
{
if (bIsManagedByGameViewportSubsystem)
{
if (UGameViewportSubsystem* Subsystem = UGameViewportSubsystem::Get(GetWorld()))
{
return Subsystem->IsWidgetAdded(this);
}
}
return false;
}
EMouseCursor::Type UWidget::GetCursor() const
{
return Cursor;
}
void UWidget::SetCursor(EMouseCursor::Type InCursor)
{
bOverride_Cursor = true;
Cursor = InCursor;
TSharedPtr<SWidget> SafeWidget = GetCachedWidget();
if ( SafeWidget.IsValid() )
{
SafeWidget->SetCursor(Cursor);
}
}
void UWidget::ResetCursor()
{
bOverride_Cursor = false;
TSharedPtr<SWidget> SafeWidget = GetCachedWidget();
if ( SafeWidget.IsValid() )
{
SafeWidget->SetCursor(TOptional<EMouseCursor::Type>());
}
}
bool UWidget::IsRendered() const
{
TSharedPtr<SWidget> SafeWidget = GetCachedWidget();
if ( SafeWidget.IsValid() )
{
return SafeWidget->GetVisibility().IsVisible() && SafeWidget->GetRenderOpacity() > 0.0f;
}
return false;
}
bool UWidget::IsVisible() const
{
TSharedPtr<SWidget> SafeWidget = GetCachedWidget();
if ( SafeWidget.IsValid() )
{
return SafeWidget->GetVisibility().IsVisible();
}
return false;
}
ESlateVisibility UWidget::GetVisibility() const
{
TSharedPtr<SWidget> SafeWidget = GetCachedWidget();
if (SafeWidget.IsValid())
{
return UWidget::ConvertRuntimeToSerializedVisibility(SafeWidget->GetVisibility());
}
return Visibility;
}
void UWidget::SetVisibility(ESlateVisibility InVisibility)
{
SetVisibilityInternal(InVisibility);
}
void UWidget::SetVisibilityInternal(ESlateVisibility InVisibility)
{
const bool bVisibilityChanged = Visibility != InVisibility;
if (bVisibilityChanged)
{
Visibility = InVisibility;
}
TSharedPtr<SWidget> SafeWidget = GetCachedWidget();
if (SafeWidget.IsValid())
{
EVisibility SlateVisibility = UWidget::ConvertSerializedVisibilityToRuntime(InVisibility);
SafeWidget->SetVisibility(SlateVisibility);
}
if (bVisibilityChanged)
{
BroadcastFieldValueChanged(FFieldNotificationClassDescriptor::Visibility);
}
}
float UWidget::GetRenderOpacity() const
{
TSharedPtr<SWidget> SafeWidget = GetCachedWidget();
if (SafeWidget.IsValid())
{
return SafeWidget->GetRenderOpacity();
}
return RenderOpacity;
}
void UWidget::SetRenderOpacity(float InRenderOpacity)
{
RenderOpacity = InRenderOpacity;
TSharedPtr<SWidget> SafeWidget = GetCachedWidget();
if (SafeWidget.IsValid())
{
SafeWidget->SetRenderOpacity(InRenderOpacity);
}
}
EWidgetClipping UWidget::GetClipping() const
{
TSharedPtr<SWidget> SafeWidget = GetCachedWidget();
if (SafeWidget.IsValid())
{
return SafeWidget->GetClipping();
}
return Clipping;
}
void UWidget::SetClipping(EWidgetClipping InClipping)
{
Clipping = InClipping;
TSharedPtr<SWidget> SafeWidget = GetCachedWidget();
if (SafeWidget.IsValid())
{
SafeWidget->SetClipping(InClipping);
}
}
PRAGMA_ENABLE_DEPRECATION_WARNINGS
EWidgetPixelSnapping UWidget::GetPixelSnapping() const
{
TSharedPtr<SWidget> SafeWidget = GetCachedWidget();
if (SafeWidget.IsValid())
{
return SafeWidget->GetPixelSnapping();
}
return PixelSnapping;
}
void UWidget::SetPixelSnapping(EWidgetPixelSnapping InPixelSnappingMethod)
{
PixelSnapping = InPixelSnappingMethod;
TSharedPtr<SWidget> SafeWidget = GetCachedWidget();
if (SafeWidget.IsValid())
{
SafeWidget->SetPixelSnapping(InPixelSnappingMethod);
}
}
void UWidget::ForceVolatile(bool bForce)
{
bIsVolatile = bForce;
TSharedPtr<SWidget> SafeWidget = GetCachedWidget();
if ( SafeWidget.IsValid() )
{
SafeWidget->ForceVolatile(bForce);
}
}
PRAGMA_DISABLE_DEPRECATION_WARNINGS
FText UWidget::GetToolTipText() const
{
return ToolTipText;
}
void UWidget::SetToolTipText(const FText& InToolTipText)
{
ToolTipText = InToolTipText;
BroadcastFieldValueChanged(FFieldNotificationClassDescriptor::ToolTipText);
TSharedPtr<SWidget> SafeWidget = GetCachedWidget();
if (SafeWidget.IsValid())
{
SafeWidget->SetToolTipText(InToolTipText);
}
}
UWidget* UWidget::GetToolTip() const
{
return ToolTipWidget;
}
void UWidget::SetToolTip(UWidget* InToolTipWidget)
{
ToolTipWidget = InToolTipWidget;
TSharedPtr<SWidget> SafeWidget = GetCachedWidget();
if ( SafeWidget.IsValid() )
{
if ( ToolTipWidget )
{
TSharedRef<SToolTip> ToolTip = SNew(SToolTip)
.TextMargin(FMargin(0))
.BorderImage(nullptr)
[
ToolTipWidget->TakeWidget()
];
SafeWidget->SetToolTip(ToolTip);
}
else
{
SafeWidget->SetToolTip(TSharedPtr<IToolTip>());
}
}
}
PRAGMA_ENABLE_DEPRECATION_WARNINGS
bool UWidget::IsHovered() const
{
TSharedPtr<SWidget> SafeWidget = GetCachedWidget();
if (SafeWidget.IsValid())
{
return SafeWidget->IsHovered();
}
return false;
}
bool UWidget::HasKeyboardFocus() const
{
TSharedPtr<SWidget> SafeWidget = GetCachedWidget();
if (SafeWidget.IsValid())
{
return SafeWidget->HasKeyboardFocus();
}
return false;
}
bool UWidget::HasMouseCapture() const
{
TSharedPtr<SWidget> SafeWidget = GetCachedWidget();
if (SafeWidget.IsValid())
{
return SafeWidget->HasMouseCapture();
}
return false;
}
bool UWidget::HasMouseCaptureByUser(int32 UserIndex, int32 PointerIndex) const
{
TSharedPtr<SWidget> SafeWidget = GetCachedWidget();
if (SafeWidget.IsValid())
{
return SafeWidget->HasMouseCaptureByUser(UserIndex, PointerIndex >= 0 ? PointerIndex : TOptional<int32>());
}
return false;
}
void UWidget::SetKeyboardFocus()
{
TSharedPtr<SWidget> SafeWidget = GetCachedWidget();
if (SafeWidget.IsValid())
{
#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
if ( !SafeWidget->SupportsKeyboardFocus() )
{
FMessageLog("PIE").Warning(FText::Format(LOCTEXT("ThisWidgetDoesntSupportFocus", "The widget {0} does not support focus. If this is a UserWidget, you should set bIsFocusable to true."), FText::FromString(GetNameSafe(this))));
}
#endif
if ( !FSlateApplication::Get().SetKeyboardFocus(SafeWidget) )
{
if ( UWorld* World = GetWorld() )
{
if ( ULocalPlayer* LocalPlayer = World->GetFirstLocalPlayerFromController() )
{
LocalPlayer->GetSlateOperations().SetUserFocus(SafeWidget.ToSharedRef(), EFocusCause::SetDirectly);
}
}
}
}
}
bool UWidget::HasUserFocus(APlayerController* PlayerController) const
{
if (PlayerController == nullptr || PlayerController->Player == nullptr || !PlayerController->IsLocalPlayerController())
{
return false;
}
TSharedPtr<SWidget> SafeWidget = GetCachedWidget();
if ( SafeWidget.IsValid() )
{
FLocalPlayerContext Context(PlayerController);
if ( ULocalPlayer* LocalPlayer = Context.GetLocalPlayer() )
{
TOptional<int32> UserIndex = FSlateApplication::Get().GetUserIndexForController(LocalPlayer->GetControllerId());
if (UserIndex.IsSet())
{
TOptional<EFocusCause> FocusCause = SafeWidget->HasUserFocus(UserIndex.GetValue());
return FocusCause.IsSet();
}
}
}
return false;
}
bool UWidget::HasAnyUserFocus() const
{
TSharedPtr<SWidget> SafeWidget = GetCachedWidget();
if ( SafeWidget.IsValid() )
{
TOptional<EFocusCause> FocusCause = SafeWidget->HasAnyUserFocus();
return FocusCause.IsSet();
}
return false;
}
bool UWidget::HasFocusedDescendants() const
{
TSharedPtr<SWidget> SafeWidget = GetCachedWidget();
if ( SafeWidget.IsValid() )
{
return SafeWidget->HasFocusedDescendants();
}
return false;
}
bool UWidget::HasUserFocusedDescendants(APlayerController* PlayerController) const
{
if ( PlayerController == nullptr || !PlayerController->IsLocalPlayerController() )
{
return false;
}
TSharedPtr<SWidget> SafeWidget = GetCachedWidget();
if ( SafeWidget.IsValid() )
{
FLocalPlayerContext Context(PlayerController);
if ( ULocalPlayer* LocalPlayer = Context.GetLocalPlayer() )
{
TOptional<int32> UserIndex = FSlateApplication::Get().GetUserIndexForController(LocalPlayer->GetControllerId());
if (UserIndex.IsSet())
{
return SafeWidget->HasUserFocusedDescendants(UserIndex.GetValue());
}
}
}
return false;
}
void UWidget::SetFocus()
{
SetUserFocus(GetOwningPlayer());
}
void UWidget::SetUserFocus(APlayerController* PlayerController)
{
if ( PlayerController == nullptr || !PlayerController->IsLocalPlayerController() || PlayerController->Player == nullptr )
{
#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
FMessageLog("PIE").Error()->AddToken(FTextToken::Create(LOCTEXT("NoPlayerControllerToFocus", "The PlayerController is not a valid local player so it can't focus on ")))->AddToken(FUObjectToken::Create(this));
#endif
return;
}
TSharedPtr<SWidget> SafeWidget = GetCachedWidget();
if ( SafeWidget.IsValid() )
{
#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
if ( !SafeWidget->SupportsKeyboardFocus() )
{
TSharedRef<FTokenizedMessage> Message = FMessageLog("PIE").Warning()->AddToken(FUObjectToken::Create(this));
#if WITH_EDITORONLY_DATA
if(UObject* GeneratedBy = WidgetGeneratedBy.Get())
{
Message->AddToken(FTextToken::Create(FText::FromString(TEXT(" in "))))->AddToken(FUObjectToken::Create(GeneratedBy));
}
#endif
if (IsA(UUserWidget::StaticClass()))
{
Message->AddToken(FTextToken::Create(LOCTEXT("UserWidgetDoesntSupportFocus", " does not support focus, you should set bIsFocusable to true.")));
}
else
{
Message->AddToken(FTextToken::Create(LOCTEXT("NonUserWidgetDoesntSupportFocus", " does not support focus.")));
}
}
#endif
if ( ULocalPlayer* LocalPlayer = PlayerController->GetLocalPlayer() )
{
TOptional<int32> UserIndex = FSlateApplication::Get().GetUserIndexForController(LocalPlayer->GetControllerId());
if (UserIndex.IsSet())
{
FReply& DelayedSlateOperations = LocalPlayer->GetSlateOperations();
if (FSlateApplication::Get().SetUserFocus(UserIndex.GetValue(), SafeWidget))
{
DelayedSlateOperations.CancelFocusRequest();
}
else
{
DelayedSlateOperations.SetUserFocus(SafeWidget.ToSharedRef());
}
}
}
}
}
void UWidget::ForceLayoutPrepass()
{
TSharedPtr<SWidget> SafeWidget = GetCachedWidget();
if (SafeWidget.IsValid())
{
SafeWidget->MarkPrepassAsDirty();
SafeWidget->SlatePrepass(SafeWidget->GetTickSpaceGeometry().Scale);
}
}
void UWidget::InvalidateLayoutAndVolatility()
{
TSharedPtr<SWidget> SafeWidget = GetCachedWidget();
if ( SafeWidget.IsValid() )
{
SafeWidget->Invalidate(EInvalidateWidgetReason::LayoutAndVolatility);
}
}
FVector2D UWidget::GetDesiredSize() const
{
TSharedPtr<SWidget> SafeWidget = GetCachedWidget();
if (SafeWidget.IsValid())
{
return SafeWidget->GetDesiredSize();
}
return FVector2D(0, 0);
}
void UWidget::SetNavigationRuleInternal(EUINavigation Direction, EUINavigationRule Rule, FName WidgetToFocus/* = NAME_None*/, UWidget* InWidget/* = nullptr*/, FCustomWidgetNavigationDelegate InCustomDelegate/* = FCustomWidgetNavigationDelegate()*/)
{
if (Navigation == nullptr)
{
Navigation = NewObject<UWidgetNavigation>(this);
}
FWidgetNavigationData NavigationData;
NavigationData.Rule = Rule;
NavigationData.WidgetToFocus = WidgetToFocus;
NavigationData.Widget = InWidget;
NavigationData.CustomDelegate = InCustomDelegate;
switch(Direction)
{
case EUINavigation::Up:
Navigation->Up = NavigationData;
break;
case EUINavigation::Down:
Navigation->Down = NavigationData;
break;
case EUINavigation::Left:
Navigation->Left = NavigationData;
break;
case EUINavigation::Right:
Navigation->Right = NavigationData;
break;
case EUINavigation::Next:
Navigation->Next = NavigationData;
break;
case EUINavigation::Previous:
Navigation->Previous = NavigationData;
break;
default:
break;
}
}
void UWidget::SetNavigationRule(EUINavigation Direction, EUINavigationRule Rule, FName WidgetToFocus)
{
SetNavigationRuleInternal(Direction, Rule, WidgetToFocus);
BuildNavigation();
}
void UWidget::SetNavigationRuleBase(EUINavigation Direction, EUINavigationRule Rule)
{
if (Rule == EUINavigationRule::Explicit || Rule == EUINavigationRule::Custom || Rule == EUINavigationRule::CustomBoundary)
{
#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
FMessageLog("PIE").Error(LOCTEXT("SetNavigationRuleBaseWrongRule", "Cannot use SetNavigationRuleBase with an Explicit or a Custom or a CustomBoundary Rule."));
#endif
return;
}
SetNavigationRuleInternal(Direction, Rule);
BuildNavigation();
}
void UWidget::SetNavigationRuleExplicit(EUINavigation Direction, UWidget* InWidget)
{
SetNavigationRuleInternal(Direction, EUINavigationRule::Explicit, NAME_None, InWidget);
BuildNavigation();
}
void UWidget::SetNavigationRuleCustom(EUINavigation Direction, FCustomWidgetNavigationDelegate InCustomDelegate)
{
SetNavigationRuleInternal(Direction, EUINavigationRule::Custom, NAME_None, nullptr, InCustomDelegate);
BuildNavigation();
}
void UWidget::SetNavigationRuleCustomBoundary(EUINavigation Direction, FCustomWidgetNavigationDelegate InCustomDelegate)
{
SetNavigationRuleInternal(Direction, EUINavigationRule::CustomBoundary, NAME_None, nullptr, InCustomDelegate);
BuildNavigation();
}
void UWidget::SetAllNavigationRules(EUINavigationRule Rule, FName WidgetToFocus)
{
SetNavigationRuleInternal(EUINavigation::Up, Rule, WidgetToFocus);
SetNavigationRuleInternal(EUINavigation::Down, Rule, WidgetToFocus);
SetNavigationRuleInternal(EUINavigation::Left, Rule, WidgetToFocus);
SetNavigationRuleInternal(EUINavigation::Right, Rule, WidgetToFocus);
SetNavigationRuleInternal(EUINavigation::Next, Rule, WidgetToFocus);
SetNavigationRuleInternal(EUINavigation::Previous, Rule, WidgetToFocus);
BuildNavigation();
}
UPanelWidget* UWidget::GetParent() const
{
if ( Slot )
{
return Slot->Parent;
}
return nullptr;
}
void UWidget::RemoveFromParent()
{
if (!HasAnyFlags(RF_BeginDestroyed))
{
if (bIsManagedByGameViewportSubsystem)
{
if (UGameViewportSubsystem* Subsystem = UGameViewportSubsystem::Get(GetWorld()))
{
Subsystem->RemoveWidget(this);
}
}
else if (UPanelWidget* CurrentParent = GetParent())
{
CurrentParent->RemoveChild(this);
}
else
{
#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
if (GetCachedWidget().IsValid() && GetCachedWidget()->GetParentWidget().IsValid() && !IsDesignTime())
{
FText WarningMessage = FText::Format(LOCTEXT("RemoveFromParentWithNoParent", "UWidget::RemoveFromParent() called on '{0}' which has no UMG parent (if it was added directly to a native Slate widget via TakeWidget() then it must be removed explicitly rather than via RemoveFromParent())"), FText::AsCultureInvariant(GetPathName()));
// @todo: nickd - we need to switch this back to a warning in engine, but info for games
FMessageLog("PIE").Info(WarningMessage);
}
#endif
}
}
}
const FGeometry& UWidget::GetCachedGeometry() const
{
return GetTickSpaceGeometry();
}
const FGeometry& UWidget::GetTickSpaceGeometry() const
{
TSharedPtr<SWidget> SafeWidget = GetCachedWidget();
if ( SafeWidget.IsValid() )
{
return SafeWidget->GetTickSpaceGeometry();
}
return SNullWidget::NullWidget->GetTickSpaceGeometry();
}
const FGeometry& UWidget::GetPaintSpaceGeometry() const
{
TSharedPtr<SWidget> SafeWidget = GetCachedWidget();
if (SafeWidget.IsValid())
{
return SafeWidget->GetPaintSpaceGeometry();
}
return SNullWidget::NullWidget->GetPaintSpaceGeometry();
}
#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
void UWidget::VerifySynchronizeProperties()
{
ensureMsgf(bRoutedSynchronizeProperties, TEXT("%s failed to route SynchronizeProperties. Please call Super::SynchronizeProperties() in your <className>::SynchronizeProperties() function."), *GetFullName());
}
#endif
void UWidget::OnWidgetRebuilt()
{
}
TSharedRef<SWidget> UWidget::TakeWidget()
{
LLM_SCOPE_BYTAG(UI_UMG);
#if WIDGET_INCLUDE_RELFECTION_METADATA
UObject* SourceAsset = GetSourceAssetOrClass();
UClass* WidgetClass = GetClass();
if(SourceAsset && WidgetClass)
{
LLM_SCOPE_DYNAMIC_STAT_OBJECTPATH(SourceAsset->GetPackage(), ELLMTagSet::Assets);
LLM_SCOPE_DYNAMIC_STAT_OBJECTPATH(WidgetClass, ELLMTagSet::AssetClasses);
UE_TRACE_METADATA_SCOPE_ASSET(SourceAsset, WidgetClass);
return TakeWidget_Private([](UUserWidget* Widget, TSharedRef<SWidget> Content) -> TSharedPtr<SObjectWidget> {
return SNew(SObjectWidget, Widget)[Content];
});
}
#endif
return TakeWidget_Private([](UUserWidget* Widget, TSharedRef<SWidget> Content) -> TSharedPtr<SObjectWidget> {
return SNew(SObjectWidget, Widget)[Content];
});
}
TSharedRef<SWidget> UWidget::TakeWidget_Private(ConstructMethodType ConstructMethod)
{
bool bNewlyCreated = false;
TSharedPtr<SWidget> PublicWidget;
// If the underlying widget doesn't exist we need to construct and cache the widget for the first run.
if (!MyWidget.IsValid())
{
PublicWidget = RebuildWidget();
#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
ensureMsgf(PublicWidget.Get() != &SNullWidget::NullWidget.Get(), TEXT("Don't return SNullWidget from RebuildWidget, because we mutate the state of the return. Return a SSpacer if you need to return a no-op widget."));
#endif
MyWidget = PublicWidget;
bNewlyCreated = true;
}
else
{
PublicWidget = MyWidget.Pin();
}
// If it is a user widget wrap it in a SObjectWidget to keep the instance from being GC'ed
if (IsA(UUserWidget::StaticClass()))
{
TSharedPtr<SObjectWidget> SafeGCWidget = MyGCWidget.Pin();
// If the GC Widget is still valid we still exist in the slate hierarchy, so just return the GC Widget.
if (SafeGCWidget.IsValid())
{
ensure(bNewlyCreated == false);
PublicWidget = SafeGCWidget;
}
else // Otherwise we need to recreate the wrapper widget
{
SafeGCWidget = ConstructMethod(Cast<UUserWidget>(this), PublicWidget.ToSharedRef());
MyGCWidget = SafeGCWidget;
PublicWidget = SafeGCWidget;
}
}
if(bWrappedByComponent)
{
// Now, if the Widget instance is wrapped by a component, add it to the hierarchy
const UWidgetTree* WidgetTree = Cast<UWidgetTree>(GetOuter());
if (const UUserWidget* UserWidget = WidgetTree ? Cast<UUserWidget>(WidgetTree->GetOuter()) : nullptr)
{
if (UUIComponentUserWidgetExtension* Extension = UserWidget->GetExtension<UUIComponentUserWidgetExtension>())
{
for (UUIComponent* Component : Extension->GetComponentsFor(this))
{
if (bNewlyCreated)
{
TSharedPtr<SWidget> SafeComponentWidget = Component->RebuildWidgetWithContent(PublicWidget.ToSharedRef());
// If the Widget is the same of null, we do nothing
if (SafeComponentWidget != PublicWidget)
{
ComponentWrapperWidget = SafeComponentWidget;
PublicWidget = SafeComponentWidget;
}
}
else if (ComponentWrapperWidget.IsValid())
{
PublicWidget = ComponentWrapperWidget.Pin();
}
}
}
}
}
#if WITH_EDITOR
if (IsDesignTime())
{
if (bNewlyCreated)
{
TSharedPtr<SWidget> SafeDesignWidget = RebuildDesignWidget(PublicWidget.ToSharedRef());
if (SafeDesignWidget != PublicWidget)
{
DesignWrapperWidget = SafeDesignWidget;
PublicWidget = SafeDesignWidget;
}
}
else if (DesignWrapperWidget.IsValid())
{
PublicWidget = DesignWrapperWidget.Pin();
}
}
#endif
if (bNewlyCreated)
{
#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
bRoutedSynchronizeProperties = false;
#endif
#if WIDGET_INCLUDE_RELFECTION_METADATA
UObject* SourceAsset = GetSourceAssetOrClass();
UClass* WidgetClass = GetClass();
// We only need to do this once, when the slate widget is created.
PublicWidget->AddMetadata<FReflectionMetaData>(MakeShared<FReflectionMetaData>(GetFName(), WidgetClass, this, SourceAsset));
#endif
SynchronizeProperties();
VerifySynchronizeProperties();
OnWidgetRebuilt();
}
return PublicWidget.ToSharedRef();
}
TSharedPtr<SWidget> UWidget::GetCachedWidget() const
{
#if WITH_EDITOR
if (DesignWrapperWidget.IsValid())
{
return DesignWrapperWidget.Pin();
}
#endif
if (ComponentWrapperWidget.IsValid())
{
return ComponentWrapperWidget.Pin();
}
if (MyGCWidget.IsValid())
{
return MyGCWidget.Pin();
}
return MyWidget.Pin();
}
bool UWidget::IsConstructed() const
{
const TSharedPtr<SWidget>& SafeWidget = GetCachedWidget();
return SafeWidget.IsValid();
}
#if WITH_EDITOR
TSharedRef<SWidget> UWidget::RebuildDesignWidget(TSharedRef<SWidget> Content)
{
return Content;
}
TSharedRef<SWidget> UWidget::CreateDesignerOutline(TSharedRef<SWidget> Content) const
{
return SNew(SOverlay)
+ SOverlay::Slot()
.HAlign(HAlign_Fill)
.VAlign(VAlign_Fill)
[
Content
]
+ SOverlay::Slot()
.HAlign(HAlign_Fill)
.VAlign(VAlign_Fill)
[
SNew(SBorder)
.AddMetaData<FInvisibleToWidgetReflectorMetaData>(FInvisibleToWidgetReflectorMetaData())
.DesiredSizeScale(FVector2D(0.0f, 0.0f))
.Visibility(HasAnyDesignerFlags(EWidgetDesignFlags::ShowOutline) ? EVisibility::HitTestInvisible : EVisibility::Collapsed)
.BorderImage(FUMGStyle::Get().GetBrush("MarchingAnts"))
];
}
#endif
UGameInstance* UWidget::GetGameInstance() const
{
if (UWorld* World = GetWorld())
{
return World->GetGameInstance();
}
return nullptr;
}
APlayerController* UWidget::GetOwningPlayer() const
{
UWidgetTree* WidgetTree = Cast<UWidgetTree>(GetOuter());
if (UUserWidget* UserWidget = WidgetTree ? Cast<UUserWidget>(WidgetTree->GetOuter()) : nullptr)
{
return UserWidget->GetOwningPlayer();
}
return nullptr;
}
ULocalPlayer* UWidget::GetOwningLocalPlayer() const
{
UWidgetTree* WidgetTree = Cast<UWidgetTree>(GetOuter());
if (UUserWidget* UserWidget = WidgetTree ? Cast<UUserWidget>(WidgetTree->GetOuter()) : nullptr)
{
return UserWidget->GetOwningLocalPlayer();
}
return nullptr;
}
#if WITH_EDITOR
#undef LOCTEXT_NAMESPACE
#define LOCTEXT_NAMESPACE "UMGEditor"
void UWidget::SetDesignerFlags(EWidgetDesignFlags NewFlags)
{
DesignerFlags = static_cast<uint8>(GetDesignerFlags() | NewFlags);
INamedSlotInterface* NamedSlotWidget = Cast<INamedSlotInterface>(this);
if (NamedSlotWidget)
{
NamedSlotWidget->SetNamedSlotDesignerFlags(NewFlags);
}
}
void UWidget::SetDisplayLabel(const FString& InDisplayLabel)
{
DisplayLabel = InDisplayLabel;
}
const FString& UWidget::GetCategoryName() const
{
return CategoryName;
}
void UWidget::SetCategoryName(const FString& InValue)
{
CategoryName = InValue;
}
bool UWidget::IsGeneratedName() const
{
if (!DisplayLabel.IsEmpty())
{
return false;
}
FString Name = GetName();
if (Name == GetClass()->GetName() || Name.StartsWith(GetClass()->GetName() + TEXT("_")))
{
return true;
}
else if (GetClass()->ClassGeneratedBy != nullptr)
{
FString BaseNameForBP = GetClass()->GetName();
BaseNameForBP.RemoveFromEnd(TEXT("_C"), ESearchCase::CaseSensitive);
if (Name == BaseNameForBP || Name.StartsWith(BaseNameForBP + TEXT("_")))
{
return true;
}
}
return false;
}
FString UWidget::GetLabelMetadata() const
{
return TEXT("");
}
FText UWidget::GetLabelText() const
{
return GetDisplayNameBase();
}
FText UWidget::GetLabelTextWithMetadata() const
{
FText Label = GetDisplayNameBase();
if (!bIsVariable || !GetLabelMetadata().IsEmpty())
{
FFormatNamedArguments Args;
Args.Add(TEXT("BaseName"), Label);
Args.Add(TEXT("Metadata"), FText::FromString(GetLabelMetadata()));
Label = FText::Format(LOCTEXT("NonVariableLabelFormat", "[{BaseName}]{Metadata}"), Args);
}
return Label;
}
FText UWidget::GetDisplayNameBase() const
{
const bool bHasDisplayLabel = !DisplayLabel.IsEmpty();
if (IsGeneratedName() && !bIsVariable)
{
return GetClass()->GetDisplayNameText();
}
else
{
return FText::FromString(bHasDisplayLabel ? DisplayLabel : GetName());
}
}
const FText UWidget::GetPaletteCategory()
{
return LOCTEXT("Uncategorized", "Uncategorized");
}
void UWidget::CreatedFromPalette()
{
// Allowing the variable creation if the setting allows it.
const UUserInterfaceSettings* UISettings = GetDefault<UUserInterfaceSettings>();
if (!UISettings->bAuthorizeAutomaticWidgetVariableCreation)
{
bIsVariable = false;
}
OnCreationFromPalette();
}
EVisibility UWidget::GetVisibilityInDesigner() const
{
return bHiddenInDesigner ? EVisibility::Collapsed : EVisibility::Visible;
}
bool UWidget::IsEditorWidget() const
{
if (UWidgetTree* WidgetTree = Cast<UWidgetTree>(GetOuter()))
{
//@TODO: DarenC - This is a bit dirty, can't find a cleaner alternative yet though.
bool bIsEditorWidgetPreview = WidgetTree->RootWidget && WidgetTree->RootWidget->WidgetGeneratedBy.IsValid();
UObject* WidgetBPObject = bIsEditorWidgetPreview ? WidgetTree->RootWidget->WidgetGeneratedBy.Get() : WidgetTree->GetOuter();
if (UUserWidgetBlueprint* WidgetBP = Cast<UUserWidgetBlueprint>(WidgetBPObject))
{
return WidgetBP->AllowEditorWidget();
}
else if (UUserWidget* UserWidget = Cast<UUserWidget>(WidgetBPObject))
{
return UserWidget->IsEditorUtility();
}
}
return false;
}
bool UWidget::IsVisibleInDesigner() const
{
if (bHiddenInDesigner)
{
return false;
}
UWidget* Parent = GetParent();
while (Parent != nullptr)
{
if (Parent->bHiddenInDesigner)
{
return false;
}
Parent = Parent->GetParent();
}
return true;
}
void UWidget::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent)
{
Super::PostEditChangeProperty(PropertyChangedEvent);
TSharedPtr<SWidget> SafeWidget = GetCachedWidget();
if (SafeWidget.IsValid())
{
SynchronizeProperties();
}
else
{
SynchronizeAccessibleData();
}
}
void UWidget::SelectByDesigner()
{
OnSelectedByDesigner();
UWidget* Parent = GetParent();
while ( Parent != nullptr )
{
Parent->OnDescendantSelectedByDesigner(this);
Parent = Parent->GetParent();
}
}
void UWidget::DeselectByDesigner()
{
OnDeselectedByDesigner();
UWidget* Parent = GetParent();
while ( Parent != nullptr )
{
Parent->OnDescendantDeselectedByDesigner(this);
Parent = Parent->GetParent();
}
}
#undef LOCTEXT_NAMESPACE
#define LOCTEXT_NAMESPACE "UMG"
#endif // WITH_EDITOR
void UWidget::PreSave(FObjectPreSaveContext ObjectSaveContext)
{
Super::PreSave(ObjectSaveContext);
// This is a failsafe to make sure all the accessibility data is copied over in case
// some rare instance isn't handled by SynchronizeProperties. It might not be necessary.
SynchronizeAccessibleData();
}
#if WITH_EDITOR
bool UWidget::Modify(bool bAlwaysMarkDirty)
{
bool Modified = Super::Modify(bAlwaysMarkDirty);
if ( Slot )
{
Slot->SetFlags(RF_Transactional);
Modified |= Slot->Modify(bAlwaysMarkDirty);
}
return Modified;
}
#endif
bool UWidget::IsChildOf(UWidget* PossibleParent)
{
UPanelWidget* Parent = GetParent();
if ( Parent == nullptr )
{
return false;
}
else if ( Parent == PossibleParent )
{
return true;
}
return Parent->IsChildOf(PossibleParent);
}
TSharedRef<SWidget> UWidget::RebuildWidget()
{
ensureMsgf(false, TEXT("You must implement RebuildWidget() in your child class"));
return SNew(SSpacer);
}
void UWidget::SynchronizeProperties()
{
#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
bRoutedSynchronizeProperties = true;
#endif
// Always sync accessible data even if the SWidget doesn't exist
SynchronizeAccessibleData();
// We want to apply the bindings to the cached widget, which could be the SWidget, or the SObjectWidget,
// in the case where it's a user widget. We always want to prefer the SObjectWidget so that bindings to
// visibility and enabled status are not stomping values setup in the root widget in the User Widget.
TSharedPtr<SWidget> SafeWidget = GetCachedWidget();
if ( !SafeWidget.IsValid() )
{
return;
}
#if WITH_EDITOR
TSharedPtr<SWidget> SafeContentWidget = MyGCWidget.IsValid() ? MyGCWidget.Pin() : MyWidget.Pin();
#endif
PRAGMA_DISABLE_DEPRECATION_WARNINGS
#if WITH_EDITOR
// Always use an enabled and visible state in the designer.
if ( IsDesignTime() )
{
SafeWidget->SetEnabled(true);
SafeWidget->SetVisibility(BIND_UOBJECT_ATTRIBUTE(EVisibility, GetVisibilityInDesigner));
}
else
#endif
{
if ( bOverride_Cursor /*|| CursorDelegate.IsBound()*/ )
{
SafeWidget->SetCursor(Cursor);// PROPERTY_BINDING(EMouseCursor::Type, Cursor));
}
SafeWidget->SetEnabled(BITFIELD_PROPERTY_BINDING( bIsEnabled ));
SafeWidget->SetVisibility(OPTIONAL_BINDING_CONVERT(ESlateVisibility, Visibility, EVisibility, ConvertVisibility));
}
#if WITH_EDITOR
// In the designer, we need to apply the clip to bounds flag to the real widget, not the designer outline.
// because we may be changing a critical default set on the base that not actually set on the outline.
// An example of this, would be changing the clipping bounds on a scrollbox. The outline never clipped to bounds
// so unless we tweak the -actual- value on the SScrollBox, the user won't see a difference in how the widget clips.
SafeContentWidget->SetClipping(Clipping);
#else
SafeWidget->SetClipping(Clipping);
#endif
SafeWidget->SetPixelSnapping(PixelSnapping);
SafeWidget->SetFlowDirectionPreference(FlowDirectionPreference);
SafeWidget->ForceVolatile(bIsVolatile);
SafeWidget->SetRenderOpacity(RenderOpacity);
UpdateRenderTransform();
SafeWidget->SetRenderTransformPivot(RenderTransformPivot);
if ( ToolTipWidgetDelegate.IsBound() && !IsDesignTime() )
{
TSharedRef<FDelegateToolTip> ToolTip = MakeShareable(new FDelegateToolTip());
ToolTip->ToolTipWidgetDelegate = ToolTipWidgetDelegate;
SafeWidget->SetToolTip(ToolTip);
}
else if ( ToolTipWidget != nullptr )
{
TSharedRef<SToolTip> ToolTip = SNew(SToolTip)
.TextMargin(FMargin(0))
.BorderImage(nullptr)
[
ToolTipWidget->TakeWidget()
];
SafeWidget->SetToolTip(ToolTip);
}
else if ( !ToolTipText.IsEmpty() || ToolTipTextDelegate.IsBound() )
{
SafeWidget->SetToolTipText(PROPERTY_BINDING(FText, ToolTipText));
}
#if WITH_ACCESSIBILITY
if (AccessibleWidgetData)
{
TSharedPtr<SWidget> AccessibleWidget = GetAccessibleWidget();
if (AccessibleWidget.IsValid())
{
AccessibleWidget->SetAccessibleBehavior((EAccessibleBehavior)AccessibleWidgetData->AccessibleBehavior, AccessibleWidgetData->CreateAccessibleTextAttribute(), EAccessibleType::Main);
AccessibleWidget->SetAccessibleBehavior((EAccessibleBehavior)AccessibleWidgetData->AccessibleSummaryBehavior, AccessibleWidgetData->CreateAccessibleSummaryTextAttribute(), EAccessibleType::Summary);
AccessibleWidget->SetCanChildrenBeAccessible(AccessibleWidgetData->bCanChildrenBeAccessible);
}
}
#endif
PRAGMA_ENABLE_DEPRECATION_WARNINGS
}
void UWidget::SynchronizeAccessibleData()
{
#if WITH_EDITORONLY_DATA
if (bOverrideAccessibleDefaults)
{
if (!AccessibleWidgetData)
{
AccessibleWidgetData = NewObject<USlateAccessibleWidgetData>(this);
}
AccessibleWidgetData->bCanChildrenBeAccessible = bCanChildrenBeAccessible;
AccessibleWidgetData->AccessibleBehavior = AccessibleBehavior;
AccessibleWidgetData->AccessibleText = AccessibleText;
AccessibleWidgetData->AccessibleTextDelegate = AccessibleTextDelegate;
AccessibleWidgetData->AccessibleSummaryBehavior = AccessibleSummaryBehavior;
AccessibleWidgetData->AccessibleSummaryText = AccessibleSummaryText;
AccessibleWidgetData->AccessibleSummaryTextDelegate = AccessibleSummaryTextDelegate;
}
else if (AccessibleWidgetData)
{
AccessibleWidgetData = nullptr;
}
#endif
}
#if WITH_ACCESSIBILITY
TSharedPtr<SWidget> UWidget::GetAccessibleWidget() const
{
return GetCachedWidget();
}
#endif
FText UWidget::GetAccessibleText() const
{
#if WITH_ACCESSIBILITY
TSharedPtr<SWidget> AccessibleWidget = GetAccessibleWidget();
if (AccessibleWidget.IsValid())
{
return AccessibleWidget->GetAccessibleText();
}
#endif
return FText::GetEmpty();
}
FText UWidget::GetAccessibleSummaryText() const
{
#if WITH_ACCESSIBILITY
TSharedPtr<SWidget> AccessibleWidget = GetAccessibleWidget();
if (AccessibleWidget.IsValid())
{
return AccessibleWidget->GetAccessibleSummary();
}
#endif
return FText::GetEmpty();
}
UObject* UWidget::GetSourceAssetOrClass() const
{
UObject* SourceAsset = nullptr;
#if WITH_EDITOR
// In editor builds we add metadata to the widget so that once hit with the widget reflector it can report
// where it comes from, what blueprint, what the name of the widget was...etc.
SourceAsset = WidgetGeneratedBy.Get();
#else
#if UE_HAS_WIDGET_GENERATED_BY_CLASS
SourceAsset = WidgetGeneratedByClass.Get();
#endif
#endif
if (!SourceAsset)
{
if (UWidget* WidgetOuter = GetTypedOuter<UWidget>())
{
return WidgetOuter->GetSourceAssetOrClass();
}
}
return SourceAsset;
}
void UWidget::BuildNavigation()
{
if ( Navigation != nullptr )
{
TSharedPtr<SWidget> SafeWidget = GetCachedWidget();
if ( SafeWidget.IsValid() )
{
TSharedPtr<FNavigationMetaData> MetaData = SafeWidget->GetMetaData<FNavigationMetaData>();
if ( !MetaData.IsValid() )
{
MetaData = MakeShared<FNavigationMetaData>();
SafeWidget->AddMetadata(MetaData.ToSharedRef());
}
Navigation->UpdateMetaData(MetaData.ToSharedRef());
}
}
}
UWorld* UWidget::GetWorld() const
{
// UWidget's are given world scope by their owning user widget. We can get that through the widget tree that should
// be the outer of this widget.
if ( UWidgetTree* OwningTree = Cast<UWidgetTree>(GetOuter()) )
{
return OwningTree->GetWorld();
}
return Super::GetWorld();
}
void UWidget::BeginDestroy()
{
if (bIsManagedByGameViewportSubsystem)
{
if (UGameViewportSubsystem* Subsystem = UGameViewportSubsystem::Get(GetWorld()))
{
Subsystem->RemoveWidget(this);
}
}
Super::BeginDestroy();
}
void UWidget::FinishDestroy()
{
Super::FinishDestroy();
DEC_DWORD_STAT(STAT_SlateUTotalWidgets);
}
EVisibility UWidget::ConvertSerializedVisibilityToRuntime(ESlateVisibility Input)
{
switch ( Input )
{
case ESlateVisibility::Visible:
return EVisibility::Visible;
case ESlateVisibility::Collapsed:
return EVisibility::Collapsed;
case ESlateVisibility::Hidden:
return EVisibility::Hidden;
case ESlateVisibility::HitTestInvisible:
return EVisibility::HitTestInvisible;
case ESlateVisibility::SelfHitTestInvisible:
return EVisibility::SelfHitTestInvisible;
default:
check(false);
return EVisibility::Visible;
}
}
ESlateVisibility UWidget::ConvertRuntimeToSerializedVisibility(const EVisibility& Input)
{
if ( Input == EVisibility::Visible )
{
return ESlateVisibility::Visible;
}
else if ( Input == EVisibility::Collapsed )
{
return ESlateVisibility::Collapsed;
}
else if ( Input == EVisibility::Hidden )
{
return ESlateVisibility::Hidden;
}
else if ( Input == EVisibility::HitTestInvisible )
{
return ESlateVisibility::HitTestInvisible;
}
else if ( Input == EVisibility::SelfHitTestInvisible )
{
return ESlateVisibility::SelfHitTestInvisible;
}
else
{
check(false);
return ESlateVisibility::Visible;
}
}
FSizeParam UWidget::ConvertSerializedSizeParamToRuntime(const FSlateChildSize& Input)
{
switch ( Input.SizeRule )
{
default:
case ESlateSizeRule::Automatic:
return FAuto();
case ESlateSizeRule::Fill:
return FStretch(Input.Value);
}
}
UWidget* UWidget::FindChildContainingDescendant(UWidget* Root, UWidget* Descendant)
{
if ( Root == nullptr )
{
return nullptr;
}
UWidget* Parent = Descendant->GetParent();
while ( Parent != nullptr )
{
// If the Descendant's parent is the root, then the child containing the descendant is the descendant.
if ( Parent == Root )
{
return Descendant;
}
Descendant = Parent;
Parent = Parent->GetParent();
}
return nullptr;
}
// TODO: Clean this up to, move it to a user interface setting, don't use a config.
FString UWidget::GetDefaultFontName()
{
FString DefaultFontName = TEXT("/Engine/EngineFonts/Roboto");
GConfig->GetString(TEXT("SlateStyle"), TEXT("DefaultFontName"), DefaultFontName, GEngineIni);
return DefaultFontName;
}
//bool UWidget::BindProperty(const FName& DestinationProperty, UObject* SourceObject, const FName& SourceProperty)
//{
// FDelegateProperty* DelegateProperty = FindFProperty<FDelegateProperty>(GetClass(), FName(*( DestinationProperty.ToString() + TEXT("Delegate") )));
//
// if ( DelegateProperty )
// {
// FDynamicPropertyPath BindingPath(SourceProperty.ToString());
// return AddBinding(DelegateProperty, SourceObject, BindingPath);
// }
//
// return false;
//}
TSubclassOf<UPropertyBinding> UWidget::FindBinderClassForDestination(FProperty* Property)
{
if (BinderClasses.IsEmpty())
{
TArray<UClass*> PropertyBindingClasses;
GetDerivedClasses(UPropertyBinding::StaticClass(), PropertyBindingClasses);
BinderClasses.Reserve(PropertyBindingClasses.Num());
for (UClass* PropertyBindingClass : PropertyBindingClasses)
{
BinderClasses.Emplace(PropertyBindingClass);
}
}
for (TSubclassOf<UPropertyBinding>& BinderClass : BinderClasses)
{
if (BinderClass.GetDefaultObject()->IsSupportedDestination(Property))
{
return BinderClass;
}
}
return nullptr;
}
static UPropertyBinding* GenerateBinder(FDelegateProperty* DelegateProperty, UObject* Container, UObject* SourceObject, const FDynamicPropertyPath& BindingPath)
{
FScriptDelegate* ScriptDelegate = DelegateProperty->GetPropertyValuePtr_InContainer(Container);
if ( ScriptDelegate )
{
// Only delegates that take no parameters have native binders.
UFunction* SignatureFunction = DelegateProperty->SignatureFunction;
if ( SignatureFunction->NumParms == 1 )
{
if ( FProperty* ReturnProperty = SignatureFunction->GetReturnProperty() )
{
TSubclassOf<UPropertyBinding> BinderClass = UWidget::FindBinderClassForDestination(ReturnProperty);
if ( BinderClass != nullptr )
{
UPropertyBinding* Binder = NewObject<UPropertyBinding>(Container, BinderClass);
Binder->SourceObject = SourceObject;
Binder->SourcePath = BindingPath;
Binder->Bind(ReturnProperty, ScriptDelegate);
return Binder;
}
}
}
}
return nullptr;
}
bool UWidget::AddBinding(FDelegateProperty* DelegateProperty, UObject* SourceObject, const FDynamicPropertyPath& BindingPath)
{
if ( UPropertyBinding* Binder = GenerateBinder(DelegateProperty, this, SourceObject, BindingPath) )
{
// Remove any existing binding object for this property.
for ( int32 BindingIndex = 0; BindingIndex < NativeBindings.Num(); BindingIndex++ )
{
if ( NativeBindings[BindingIndex]->DestinationProperty == DelegateProperty->GetFName() )
{
NativeBindings.RemoveAt(BindingIndex);
break;
}
}
NativeBindings.Add(Binder);
// Only notify the bindings have changed if we've already create the underlying slate widget.
if ( MyWidget.IsValid() )
{
OnBindingChanged(DelegateProperty->GetFName());
}
return true;
}
return false;
}
FDelegateHandle UWidget::RegisterPostStateListener(const FOnWidgetStateBroadcast::FDelegate& ListenerDelegate, bool bBroadcastCurrentState)
{
if (!bWidgetStateInitialized)
{
MyWidgetStateBitfield = UWidgetStateSettings::Get()->GetInitialRegistrationBitfield(this);
bWidgetStateInitialized = true;
}
if (bBroadcastCurrentState)
{
ListenerDelegate.ExecuteIfBound(this, MyWidgetStateBitfield);
}
return PostWidgetStateChanged.Add(ListenerDelegate);
}
void UWidget::UnregisterPostStateListener(const FDelegateHandle& ListenerDelegate)
{
PostWidgetStateChanged.Remove(ListenerDelegate);
}
void UWidget::OnBindingChanged(const FName& Property)
{
}
void UWidget::BroadcastBinaryPostStateChange(const FWidgetStateBitfield& StateChange, bool bInValue)
{
if (bShouldBroadcastState && bWidgetStateInitialized)
{
MyWidgetStateBitfield.SetBinaryState(StateChange, bInValue);
PostWidgetStateChanged.Broadcast(this, MyWidgetStateBitfield);
}
}
void UWidget::BroadcastEnumPostStateChange(const FWidgetStateBitfield& StateChange)
{
}
namespace UE::UMG::Private
{
UWidgetFieldNotificationExtension* FindOrAddWidgetNotifyExtension(UWidget* Widget)
{
if (UUserWidget* UserWidget = Cast<UUserWidget>(Widget))
{
if (UWidgetFieldNotificationExtension* Extension = UserWidget->GetExtension<UWidgetFieldNotificationExtension>())
{
return Extension;
}
return UserWidget->AddExtension<UWidgetFieldNotificationExtension>();
}
else if (UWidgetTree* WidgetTree = Cast<UWidgetTree>(Widget->GetOuter()))
{
if (UUserWidget* InnerUserWidget = Cast<UUserWidget>(WidgetTree->GetOuter()))
{
if (UWidgetFieldNotificationExtension* Extension = InnerUserWidget->GetExtension<UWidgetFieldNotificationExtension>())
{
return Extension;
}
return InnerUserWidget->AddExtension<UWidgetFieldNotificationExtension>();
}
}
return nullptr;
}
UWidgetFieldNotificationExtension* FindWidgetNotifyExtension(const UWidget* Widget)
{
if (const UUserWidget* UserWidget = Cast<const UUserWidget>(Widget))
{
if (UWidgetFieldNotificationExtension* Extension = UserWidget->GetExtension<UWidgetFieldNotificationExtension>())
{
return Extension;
}
}
else if (const UWidgetTree* WidgetTree = Cast<const UWidgetTree>(Widget->GetOuter()))
{
if (const UUserWidget* InnerUserWidget = Cast<const UUserWidget>(WidgetTree->GetOuter()))
{
if (UWidgetFieldNotificationExtension* Extension = InnerUserWidget->GetExtension<UWidgetFieldNotificationExtension>())
{
return Extension;
}
}
}
return nullptr;
}
}
FDelegateHandle UWidget::AddFieldValueChangedDelegate(UE::FieldNotification::FFieldId InFieldId, FFieldValueChangedDelegate InNewDelegate)
{
FDelegateHandle Result;
if (InFieldId.IsValid())
{
if (UWidgetFieldNotificationExtension* Extension = UE::UMG::Private::FindOrAddWidgetNotifyExtension(this))
{
Result = Extension->AddFieldValueChangedDelegate(this, InFieldId, MoveTemp(InNewDelegate));
if (Result.IsValid())
{
EnabledFieldNotifications.PadToNum(InFieldId.GetIndex() + 1, false);
EnabledFieldNotifications[InFieldId.GetIndex()] = true;
}
}
}
return Result;
}
void UWidget::K2_AddFieldValueChangedDelegate(FFieldNotificationId InFieldId, FFieldValueChangedDynamicDelegate InDelegate)
{
if (InFieldId.IsValid())
{
const UE::FieldNotification::FFieldId FieldId = GetFieldNotificationDescriptor().GetField(GetClass(), InFieldId.FieldName);
if (ensureMsgf(FieldId.IsValid(), TEXT("The field should be compiled correctly.")))
{
if (UWidgetFieldNotificationExtension* Extension = UE::UMG::Private::FindOrAddWidgetNotifyExtension(this))
{
if (Extension->AddFieldValueChangedDelegate(this, FieldId, InDelegate).IsValid())
{
EnabledFieldNotifications.PadToNum(FieldId.GetIndex() + 1, false);
EnabledFieldNotifications[FieldId.GetIndex()] = true;
}
}
}
}
}
bool UWidget::RemoveFieldValueChangedDelegate(UE::FieldNotification::FFieldId InFieldId, FDelegateHandle InHandle)
{
bool bResult = false;
if (InFieldId.IsValid() && InHandle.IsValid() && EnabledFieldNotifications.IsValidIndex(InFieldId.GetIndex()) && EnabledFieldNotifications[InFieldId.GetIndex()])
{
UWidgetFieldNotificationExtension* Extension = UE::UMG::Private::FindWidgetNotifyExtension(this);
checkf(Extension, TEXT("If the EnabledFieldNotifications is valid, then the Extension must also be valid."));
UWidgetFieldNotificationExtension::FRemoveFromResult RemoveResult = Extension->RemoveFieldValueChangedDelegate(this, InFieldId, InHandle);
bResult = RemoveResult.bRemoved;
EnabledFieldNotifications[InFieldId.GetIndex()] = RemoveResult.bHasOtherBoundDelegates;
}
return bResult;
}
void UWidget::K2_RemoveFieldValueChangedDelegate(FFieldNotificationId InFieldId, FFieldValueChangedDynamicDelegate InDelegate)
{
if (InFieldId.IsValid())
{
const UE::FieldNotification::FFieldId FieldId = GetFieldNotificationDescriptor().GetField(GetClass(), InFieldId.FieldName);
if (ensureMsgf(FieldId.IsValid(), TEXT("The field should be compiled correctly.")))
{
if (EnabledFieldNotifications.IsValidIndex(FieldId.GetIndex()) && EnabledFieldNotifications[FieldId.GetIndex()])
{
UWidgetFieldNotificationExtension* Extension = UE::UMG::Private::FindWidgetNotifyExtension(this);
checkf(Extension, TEXT("If the EnabledFieldNotifications is valid, then the Extension must also be valid."));
UWidgetFieldNotificationExtension::FRemoveFromResult RemoveResult = Extension->RemoveFieldValueChangedDelegate(this, FieldId, InDelegate);
EnabledFieldNotifications[FieldId.GetIndex()] = RemoveResult.bHasOtherBoundDelegates;
}
}
}
}
int32 UWidget::RemoveAllFieldValueChangedDelegates(FDelegateUserObjectConst InUserObject)
{
int32 bResult = 0;
if (InUserObject)
{
if (UWidgetFieldNotificationExtension* Extension = UE::UMG::Private::FindWidgetNotifyExtension(this))
{
UWidgetFieldNotificationExtension::FRemoveAllResult RemoveResult = Extension->RemoveAllFieldValueChangedDelegates(this, InUserObject);
bResult = RemoveResult.RemoveCount;
EnabledFieldNotifications = RemoveResult.HasFields;
}
}
return bResult;
}
int32 UWidget::RemoveAllFieldValueChangedDelegates(UE::FieldNotification::FFieldId InFieldId, FDelegateUserObjectConst InUserObject)
{
int32 bResult = 0;
if (InUserObject)
{
if (UWidgetFieldNotificationExtension* Extension = UE::UMG::Private::FindWidgetNotifyExtension(this))
{
UWidgetFieldNotificationExtension::FRemoveAllResult RemoveResult = Extension->RemoveAllFieldValueChangedDelegates(this, InFieldId, InUserObject);
bResult = RemoveResult.RemoveCount;
EnabledFieldNotifications = RemoveResult.HasFields;
}
}
return bResult;
}
void UWidget::BroadcastFieldValueChanged(UE::FieldNotification::FFieldId InFieldId)
{
if (InFieldId.IsValid() && EnabledFieldNotifications.IsValidIndex(InFieldId.GetIndex()) && EnabledFieldNotifications[InFieldId.GetIndex()])
{
UWidgetFieldNotificationExtension* Extension = UE::UMG::Private::FindWidgetNotifyExtension(this);
checkf(Extension, TEXT("If the EnabledFieldNotifications is valid, then the Extension must also be valid."));
Extension->BroadcastFieldValueChanged(this, InFieldId);
}
}
void UWidget::K2_BroadcastFieldValueChanged(FFieldNotificationId InFieldId)
{
if (InFieldId.IsValid())
{
const UE::FieldNotification::FFieldId FieldId = GetFieldNotificationDescriptor().GetField(GetClass(), InFieldId.FieldName);
if (ensureMsgf(FieldId.IsValid(), TEXT("The field should be compiled correctly.")))
{
BroadcastFieldValueChanged(FieldId);
}
}
}
#undef LOCTEXT_NAMESPACE