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

431 lines
10 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "Components/Border.h"
#include "Slate/SlateBrushAsset.h"
#include "Materials/MaterialInterface.h"
#include "Engine/Texture2D.h"
#include "Materials/MaterialInstanceDynamic.h"
#include "Types/ReflectionMetadata.h"
#include "Widgets/SNullWidget.h"
#include "Widgets/DeclarativeSyntaxSupport.h"
#include "Widgets/Layout/SBorder.h"
#include "Components/BorderSlot.h"
#include "ObjectEditorUtils.h"
#include UE_INLINE_GENERATED_CPP_BY_NAME(Border)
#define LOCTEXT_NAMESPACE "UMG"
/////////////////////////////////////////////////////
// UBorder
UBorder::UBorder(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{
bIsVariable = false;
PRAGMA_DISABLE_DEPRECATION_WARNINGS
ContentColorAndOpacity = FLinearColor::White;
BrushColor = FLinearColor::White;
Padding = FMargin(4, 2);
HorizontalAlignment = HAlign_Fill;
VerticalAlignment = VAlign_Fill;
DesiredSizeScale = FVector2D(1, 1);
bShowEffectWhenDisabled = true;
PRAGMA_ENABLE_DEPRECATION_WARNINGS
}
void UBorder::ReleaseSlateResources(bool bReleaseChildren)
{
Super::ReleaseSlateResources(bReleaseChildren);
MyBorder.Reset();
}
TSharedRef<SWidget> UBorder::RebuildWidget()
{
MyBorder = SNew(SBorder)
.FlipForRightToLeftFlowDirection(bFlipForRightToLeftFlowDirection);
if ( GetChildrenCount() > 0 )
{
Cast<UBorderSlot>(GetContentSlot())->BuildSlot(MyBorder.ToSharedRef());
}
return MyBorder.ToSharedRef();
}
void UBorder::SynchronizeProperties()
{
Super::SynchronizeProperties();
if (!MyBorder.IsValid())
{
return;
}
PRAGMA_DISABLE_DEPRECATION_WARNINGS
TAttribute<FLinearColor> ContentColorAndOpacityBinding = PROPERTY_BINDING(FLinearColor, ContentColorAndOpacity);
TAttribute<FSlateColor> BrushColorBinding = OPTIONAL_BINDING_CONVERT(FLinearColor, BrushColor, FSlateColor, ConvertLinearColorToSlateColor);
TAttribute<const FSlateBrush*> ImageBinding = OPTIONAL_BINDING_CONVERT(FSlateBrush, Background, const FSlateBrush*, ConvertImage);
MyBorder->SetPadding(Padding);
MyBorder->SetBorderBackgroundColor(BrushColorBinding);
MyBorder->SetColorAndOpacity(ContentColorAndOpacityBinding);
MyBorder->SetBorderImage(ImageBinding);
MyBorder->SetDesiredSizeScale(DesiredSizeScale);
MyBorder->SetShowEffectWhenDisabled(bShowEffectWhenDisabled != 0);
PRAGMA_ENABLE_DEPRECATION_WARNINGS
MyBorder->SetOnMouseButtonDown(BIND_UOBJECT_DELEGATE(FPointerEventHandler, HandleMouseButtonDown));
MyBorder->SetOnMouseButtonUp(BIND_UOBJECT_DELEGATE(FPointerEventHandler, HandleMouseButtonUp));
MyBorder->SetOnMouseMove(BIND_UOBJECT_DELEGATE(FPointerEventHandler, HandleMouseMove));
MyBorder->SetOnMouseDoubleClick(BIND_UOBJECT_DELEGATE(FPointerEventHandler, HandleMouseDoubleClick));
}
UClass* UBorder::GetSlotClass() const
{
return UBorderSlot::StaticClass();
}
void UBorder::OnSlotAdded(UPanelSlot* InSlot)
{
PRAGMA_DISABLE_DEPRECATION_WARNINGS
// Copy the content properties into the new slot so that it matches what has been setup
// so far by the user.
UBorderSlot* BorderSlot = CastChecked<UBorderSlot>(InSlot);
BorderSlot->Padding = Padding;
BorderSlot->HorizontalAlignment = HorizontalAlignment;
BorderSlot->VerticalAlignment = VerticalAlignment;
PRAGMA_ENABLE_DEPRECATION_WARNINGS
// Add the child to the live slot if it already exists
if ( MyBorder.IsValid() )
{
// Construct the underlying slot.
BorderSlot->BuildSlot(MyBorder.ToSharedRef());
}
}
void UBorder::OnSlotRemoved(UPanelSlot* InSlot)
{
// Remove the widget from the live slot if it exists.
if ( MyBorder.IsValid() )
{
MyBorder->SetContent(SNullWidget::NullWidget);
}
}
PRAGMA_DISABLE_DEPRECATION_WARNINGS
FLinearColor UBorder::GetContentColorAndOpacity() const
{
if (MyBorder.IsValid())
{
return MyBorder->GetColorAndOpacity();
}
return ContentColorAndOpacity;
}
void UBorder::SetContentColorAndOpacity(FLinearColor Color)
{
ContentColorAndOpacity = Color;
if ( MyBorder.IsValid() )
{
MyBorder->SetColorAndOpacity(Color);
}
}
FMargin UBorder::GetPadding() const
{
return Padding;
}
void UBorder::SetPadding(FMargin InPadding)
{
Padding = InPadding;
if ( MyBorder.IsValid() )
{
MyBorder->SetPadding(InPadding);
}
}
EHorizontalAlignment UBorder::GetHorizontalAlignment() const
{
return HorizontalAlignment;
}
void UBorder::SetHorizontalAlignment(EHorizontalAlignment InHorizontalAlignment)
{
HorizontalAlignment = InHorizontalAlignment;
if (MyBorder.IsValid())
{
MyBorder->SetHAlign(InHorizontalAlignment);
}
}
EVerticalAlignment UBorder::GetVerticalAlignment() const
{
return VerticalAlignment;
}
void UBorder::SetVerticalAlignment(EVerticalAlignment InVerticalAlignment)
{
VerticalAlignment = InVerticalAlignment;
if ( MyBorder.IsValid() )
{
MyBorder->SetVAlign(InVerticalAlignment);
}
}
FLinearColor UBorder::GetBrushColor() const
{
return BrushColor;
}
void UBorder::SetBrushColor(FLinearColor Color)
{
BrushColor = Color;
if ( MyBorder.IsValid() )
{
MyBorder->SetBorderBackgroundColor(Color);
}
}
PRAGMA_ENABLE_DEPRECATION_WARNINGS
FReply UBorder::HandleMouseButtonDown(const FGeometry& Geometry, const FPointerEvent& MouseEvent)
{
if ( OnMouseButtonDownEvent.IsBound() )
{
return OnMouseButtonDownEvent.Execute(Geometry, MouseEvent).NativeReply;
}
return FReply::Unhandled();
}
FReply UBorder::HandleMouseButtonUp(const FGeometry& Geometry, const FPointerEvent& MouseEvent)
{
if ( OnMouseButtonUpEvent.IsBound() )
{
return OnMouseButtonUpEvent.Execute(Geometry, MouseEvent).NativeReply;
}
return FReply::Unhandled();
}
FReply UBorder::HandleMouseMove(const FGeometry& Geometry, const FPointerEvent& MouseEvent)
{
if ( OnMouseMoveEvent.IsBound() )
{
return OnMouseMoveEvent.Execute(Geometry, MouseEvent).NativeReply;
}
return FReply::Unhandled();
}
FReply UBorder::HandleMouseDoubleClick(const FGeometry& Geometry, const FPointerEvent& MouseEvent)
{
if ( OnMouseDoubleClickEvent.IsBound() )
{
return OnMouseDoubleClickEvent.Execute(Geometry, MouseEvent).NativeReply;
}
return FReply::Unhandled();
}
void UBorder::SetBrush(const FSlateBrush& Brush)
{
Background = Brush;
if ( MyBorder.IsValid() )
{
MyBorder->SetBorderImage(&Background);
}
}
void UBorder::SetBrushFromAsset(USlateBrushAsset* Asset)
{
Background = Asset ? Asset->Brush : FSlateBrush();
if ( MyBorder.IsValid() )
{
MyBorder->SetBorderImage(&Background);
}
}
void UBorder::SetBrushFromTexture(UTexture2D* Texture)
{
Background.SetResourceObject(Texture);
if ( MyBorder.IsValid() )
{
MyBorder->SetBorderImage(&Background);
}
}
void UBorder::SetBrushFromMaterial(UMaterialInterface* Material)
{
if (!Material)
{
UE_LOG(LogSlate, Log, TEXT("UBorder::SetBrushFromMaterial. Incoming material is null. %s"), *GetPathName());
}
Background.SetResourceObject(Material);
//TODO UMG Check if the material can be used with the UI
if ( MyBorder.IsValid() )
{
MyBorder->SetBorderImage(&Background);
}
}
PRAGMA_DISABLE_DEPRECATION_WARNINGS
bool UBorder::GetShowEffectWhenDisabled() const
{
return bShowEffectWhenDisabled;
}
void UBorder::SetShowEffectWhenDisabled(bool bInShowEffectWhenDisabled)
{
bShowEffectWhenDisabled = bInShowEffectWhenDisabled;
if(MyBorder)
{
MyBorder->SetShowEffectWhenDisabled(bShowEffectWhenDisabled != 0);
}
}
PRAGMA_ENABLE_DEPRECATION_WARNINGS
UMaterialInstanceDynamic* UBorder::GetDynamicMaterial()
{
UMaterialInterface* Material = nullptr;
UObject* Resource = Background.GetResourceObject();
Material = Cast<UMaterialInterface>(Resource);
if ( Material )
{
UMaterialInstanceDynamic* DynamicMaterial = Cast<UMaterialInstanceDynamic>(Material);
if ( !DynamicMaterial )
{
DynamicMaterial = UMaterialInstanceDynamic::Create(Material, this);
Background.SetResourceObject(DynamicMaterial);
if ( MyBorder.IsValid() )
{
MyBorder->SetBorderImage(&Background);
}
}
return DynamicMaterial;
}
//TODO UMG can we do something for textures? General purpose dynamic material for them?
return nullptr;
}
PRAGMA_DISABLE_DEPRECATION_WARNINGS
FVector2D UBorder::GetDesiredSizeScale() const
{
return DesiredSizeScale;
}
void UBorder::SetDesiredSizeScale(FVector2D InScale)
{
DesiredSizeScale = InScale;
if (MyBorder.IsValid())
{
MyBorder->SetDesiredSizeScale(InScale);
}
}
PRAGMA_ENABLE_DEPRECATION_WARNINGS
const FSlateBrush* UBorder::ConvertImage(TAttribute<FSlateBrush> InImageAsset) const
{
UBorder* MutableThis = const_cast<UBorder*>( this );
MutableThis->Background = InImageAsset.Get();
return &Background;
}
void UBorder::PostLoad()
{
Super::PostLoad();
if ( GetChildrenCount() > 0 )
{
//TODO UMG Pre-Release Upgrade, now have slots of their own. Convert existing slot to new slot.
if ( UPanelSlot* PanelSlot = GetContentSlot() )
{
UBorderSlot* BorderSlot = Cast<UBorderSlot>(PanelSlot);
if ( BorderSlot == NULL )
{
BorderSlot = NewObject<UBorderSlot>(this);
BorderSlot->Content = GetContentSlot()->Content;
BorderSlot->Content->Slot = BorderSlot;
Slots[0] = BorderSlot;
}
}
}
}
#if WITH_EDITOR
void UBorder::PostEditChangeProperty(struct FPropertyChangedEvent& PropertyChangedEvent)
{
Super::PostEditChangeProperty(PropertyChangedEvent);
static bool IsReentrant = false;
if ( !IsReentrant )
{
IsReentrant = true;
if ( PropertyChangedEvent.Property )
{
static const FName PaddingName("Padding");
static const FName HorizontalAlignmentName("HorizontalAlignment");
static const FName VerticalAlignmentName("VerticalAlignment");
FName PropertyName = PropertyChangedEvent.Property->GetFName();
if ( UBorderSlot* BorderSlot = Cast<UBorderSlot>(GetContentSlot()) )
{
if (PropertyName == PaddingName)
{
FObjectEditorUtils::MigratePropertyValue(this, PaddingName, BorderSlot, PaddingName);
}
else if (PropertyName == HorizontalAlignmentName)
{
FObjectEditorUtils::MigratePropertyValue(this, HorizontalAlignmentName, BorderSlot, HorizontalAlignmentName);
}
else if (PropertyName == VerticalAlignmentName)
{
FObjectEditorUtils::MigratePropertyValue(this, VerticalAlignmentName, BorderSlot, VerticalAlignmentName);
}
}
}
IsReentrant = false;
}
}
const FText UBorder::GetPaletteCategory()
{
return LOCTEXT("Common", "Common");
}
#endif
/////////////////////////////////////////////////////
#undef LOCTEXT_NAMESPACE