Files
UnrealEngine/Engine/Source/Runtime/Slate/Private/Widgets/SCanvas.cpp
2025-05-18 13:04:45 +08:00

167 lines
4.6 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "Widgets/SCanvas.h"
#include "Types/PaintArgs.h"
#include "Layout/ArrangedChildren.h"
SLATE_IMPLEMENT_WIDGET(SCanvas)
void SCanvas::PrivateRegisterAttributes(FSlateAttributeInitializer& AttributeInitializer)
{
FSlateWidgetSlotAttributeInitializer Initializer = SLATE_ADD_PANELCHILDREN_DEFINITION(AttributeInitializer, Children);
FSlot::RegisterAttributes(Initializer);
}
void SCanvas::FSlot::RegisterAttributes(FSlateWidgetSlotAttributeInitializer& AttributeInitializer)
{
TWidgetSlotWithAttributeSupport::RegisterAttributes(AttributeInitializer);
SLATE_ADD_SLOT_ATTRIBUTE_DEFINITION_WITH_NAME(FSlot, AttributeInitializer, "Slot.Size", Size, EInvalidateWidgetReason::Paint);
SLATE_ADD_SLOT_ATTRIBUTE_DEFINITION_WITH_NAME(FSlot, AttributeInitializer, "Slot.Position", Position, EInvalidateWidgetReason::Paint)
.UpdatePrerequisite("Slot.Size");
}
void SCanvas::FSlot::Construct(const FChildren& SlotOwner, FSlotArguments&& InArg)
{
TWidgetSlotWithAttributeSupport<FSlot>::Construct(SlotOwner, MoveTemp(InArg));
if (InArg._Size.IsSet())
{
Size.Assign(*this, MoveTemp(InArg._Size));
}
if (InArg._Position.IsSet())
{
Position.Assign(*this, MoveTemp(InArg._Position));
}
TAlignmentWidgetSlotMixin<FSlot>::ConstructMixin(SlotOwner, MoveTemp(InArg));
}
SCanvas::SCanvas()
: Children(this, GET_MEMBER_NAME_CHECKED(SCanvas, Children))
{
SetCanTick(false);
bCanSupportFocus = false;
}
SCanvas::~SCanvas() = default;
void SCanvas::Construct( const SCanvas::FArguments& InArgs )
{
Children.AddSlots(MoveTemp(const_cast<TArray<FSlot::FSlotArguments>&>(InArgs._Slots)));
}
SCanvas::FSlot::FSlotArguments SCanvas::Slot()
{
return FSlot::FSlotArguments(MakeUnique<FSlot>());
}
SCanvas::FScopedWidgetSlotArguments SCanvas::AddSlot()
{
return FScopedWidgetSlotArguments{ MakeUnique<FSlot>(), Children, INDEX_NONE };
}
void SCanvas::ClearChildren( )
{
Children.Empty();
}
int32 SCanvas::RemoveSlot( const TSharedRef<SWidget>& SlotWidget )
{
return Children.Remove(SlotWidget);
}
void SCanvas::OnArrangeChildren( const FGeometry& AllottedGeometry, FArrangedChildren& ArrangedChildren ) const
{
if (Children.Num() > 0)
{
for (int32 ChildIndex = 0; ChildIndex < Children.Num(); ++ChildIndex)
{
const SCanvas::FSlot& CurChild = Children[ChildIndex];
const FVector2D Size = CurChild.GetSize();
//Handle HAlignment
FVector2D Offset(0.0f, 0.0f);
switch (CurChild.GetHorizontalAlignment())
{
case HAlign_Center:
Offset.X = -Size.X / 2.0f;
break;
case HAlign_Right:
Offset.X = -Size.X;
break;
case HAlign_Fill:
case HAlign_Left:
break;
}
//handle VAlignment
switch (CurChild.GetVerticalAlignment())
{
case VAlign_Bottom:
Offset.Y = -Size.Y;
break;
case VAlign_Center:
Offset.Y = -Size.Y / 2.0f;
break;
case VAlign_Top:
case VAlign_Fill:
break;
}
// Add the information about this child to the output list (ArrangedChildren)
ArrangedChildren.AddWidget( AllottedGeometry.MakeChild(
// The child widget being arranged
CurChild.GetWidget(),
// Child's local position (i.e. position within parent)
CurChild.GetPosition() + Offset,
// Child's size
Size
));
}
}
}
int32 SCanvas::OnPaint( const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyCullingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled ) const
{
FArrangedChildren ArrangedChildren(EVisibility::Visible);
this->ArrangeChildren(AllottedGeometry, ArrangedChildren);
// Because we paint multiple children, we must track the maximum layer id that they produced in case one of our parents
// wants to an overlay for all of its contents.
int32 MaxLayerId = LayerId;
const bool bForwardedEnabled = ShouldBeEnabled(bParentEnabled);
const FPaintArgs NewArgs = Args.WithNewParent(this);
for (int32 ChildIndex = 0; ChildIndex < ArrangedChildren.Num(); ++ChildIndex)
{
FArrangedWidget& CurWidget = ArrangedChildren[ChildIndex];
if ( !IsChildWidgetCulled(MyCullingRect, CurWidget) )
{
const int32 CurWidgetsMaxLayerId = CurWidget.Widget->Paint(NewArgs, CurWidget.Geometry, MyCullingRect, OutDrawElements, MaxLayerId + 1, InWidgetStyle, bForwardedEnabled);
MaxLayerId = FMath::Max(MaxLayerId, CurWidgetsMaxLayerId);
}
else
{
}
}
return MaxLayerId;
}
FVector2D SCanvas::ComputeDesiredSize( float ) const
{
// Canvas widgets have no desired size -- their size is always determined by their container
return FVector2D::ZeroVector;
}
FChildren* SCanvas::GetChildren()
{
return &Children;
}