Files
UnrealEngine/Engine/Source/Developer/ToolWidgets/Private/Overlay/SDraggableBoxOverlay.cpp
Brandyn / Techy fcc1b09210 init
2026-04-04 15:40:51 -05:00

233 lines
5.7 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "Overlay/SDraggableBoxOverlay.h"
#include "Framework/Application/SlateApplication.h"
#include "Overlay/DragBoxPosition.h"
#include "Overlay/SDraggableBox.h"
#include "Widgets/Layout/SBox.h"
#include "Widgets/SWindow.h"
namespace UE::ToolWidgets
{
namespace DraggableBoxDetail
{
static constexpr float DraggableBorderArea = 3.f;
}
void SDraggableBoxOverlay::Construct(const FArguments& InArgs)
{
HorizontalAlignment = InArgs._HAlign;
VerticalAlignment = InArgs._VAlign;
ChildSlot
[
SAssignNew(Container, SBox)
.HAlign(HorizontalAlignment)
.VAlign(VerticalAlignment)
[
SAssignNew(DraggableBox, SDraggableBox, SharedThis(this))
.IsDraggable(InArgs._IsDraggable)
.OnUserDraggedToNewPosition(InArgs._OnUserDraggedToNewPosition)
[
InArgs._Content.Widget
]
]
];
SetBoxAlignmentOffset(InArgs._InitialAlignmentOffset, false);
}
FVector2f SDraggableBoxOverlay::GetBoxAlignmentOffset() const
{
FVector2f AlignmentOffset = FVector2f::ZeroVector;
if (Container.IsValid())
{
switch (HorizontalAlignment)
{
case EHorizontalAlignment::HAlign_Left:
AlignmentOffset.X = Padding.Left;
break;
case EHorizontalAlignment::HAlign_Right:
AlignmentOffset.X = Padding.Right;
break;
default: break;
}
switch (VerticalAlignment)
{
case EVerticalAlignment::VAlign_Top:
AlignmentOffset.Y = Padding.Top;
break;
case EVerticalAlignment::VAlign_Bottom:
AlignmentOffset.Y = Padding.Bottom;
break;
default: break;
}
}
return AlignmentOffset;
}
void SDraggableBoxOverlay::SetBoxAlignmentOffset(const FVector2f& InOffset, bool bInRecomputeAnchorPoints)
{
if (!Container.IsValid() || !DraggableBox.IsValid())
{
return;
}
FVector2f ConstrainedOffset = {
FMath::Max(InOffset.X, DraggableBoxDetail::DraggableBorderArea),
FMath::Max(InOffset.Y, DraggableBoxDetail::DraggableBorderArea)
};
if (bInRecomputeAnchorPoints)
{
ConstrainedOffset = RecomputeAnchorPoints(ConstrainedOffset);
}
switch (HorizontalAlignment)
{
case EHorizontalAlignment::HAlign_Left:
Padding.Left = ConstrainedOffset.X;
Padding.Right = 0.f;
break;
case EHorizontalAlignment::HAlign_Right:
Padding.Left = 0.f;
Padding.Right = ConstrainedOffset.X;
break;
default: break;
}
switch (VerticalAlignment)
{
case EVerticalAlignment::VAlign_Top:
Padding.Top = ConstrainedOffset.Y;
Padding.Bottom = 0.f;
break;
case EVerticalAlignment::VAlign_Bottom:
Padding.Top = 0.f;
Padding.Bottom = ConstrainedOffset.Y;
break;
default: break;
}
if (Container.IsValid())
{
Container->SetPadding(Padding);
}
}
EHorizontalAlignment SDraggableBoxOverlay::GetBoxHorizontalAlignment() const
{
return HorizontalAlignment;
}
void SDraggableBoxOverlay::SetBoxHorizontalAlignment(EHorizontalAlignment InAlignment)
{
HorizontalAlignment = InAlignment;
if (Container.IsValid())
{
Container->SetHAlign(InAlignment);
}
}
EVerticalAlignment SDraggableBoxOverlay::GetBoxVerticalAlignment() const
{
return VerticalAlignment;
}
void SDraggableBoxOverlay::SetBoxVerticalAlignment(EVerticalAlignment InAlignment)
{
VerticalAlignment = InAlignment;
if (Container.IsValid())
{
Container->SetVAlign(InAlignment);
}
}
FMargin SDraggableBoxOverlay::GetPadding() const
{
return Padding;
}
FVector2f SDraggableBoxOverlay::RecomputeAnchorPoints(const FVector2f& InOffset)
{
const FGeometry& MyGeometry = GetTickSpaceGeometry();
const FVector2f AvailableSpace = (MyGeometry.GetAbsoluteSize() - DraggableBox->GetTickSpaceGeometry().GetAbsoluteSize())
* (MyGeometry.GetLocalSize() / MyGeometry.GetAbsoluteSize());
const FVector2f MidPoint = AvailableSpace * 0.5f;
if (!ensure(!MidPoint.ContainsNaN())) // Don't call this during construction because the geometry is not initialized, yet.
{
return InOffset;
}
FVector2f ConstrainedOffset = InOffset;
ConstrainedOffset.X = FMath::Min(ConstrainedOffset.X, AvailableSpace.X);
ConstrainedOffset.Y = FMath::Min(ConstrainedOffset.Y, AvailableSpace.Y);
if (ConstrainedOffset.X > MidPoint.X)
{
ConstrainedOffset.X = FMath::Max(AvailableSpace.X - ConstrainedOffset.X, DraggableBoxDetail::DraggableBorderArea); // Circle value around
switch (HorizontalAlignment)
{
case EHorizontalAlignment::HAlign_Left:
SetBoxHorizontalAlignment(EHorizontalAlignment::HAlign_Right);
break;
case EHorizontalAlignment::HAlign_Right:
SetBoxHorizontalAlignment(EHorizontalAlignment::HAlign_Left);
break;
default:
// Do nothing
break;
}
}
if (ConstrainedOffset.Y > MidPoint.Y)
{
ConstrainedOffset.Y = FMath::Max(AvailableSpace.Y - ConstrainedOffset.Y, DraggableBoxDetail::DraggableBorderArea); // Circle value around
switch (VerticalAlignment)
{
case EVerticalAlignment::VAlign_Top:
SetBoxVerticalAlignment(EVerticalAlignment::VAlign_Bottom);
break;
case EVerticalAlignment::VAlign_Bottom:
SetBoxVerticalAlignment(EVerticalAlignment::VAlign_Top);
break;
default:
// Do nothing
break;
}
}
return ConstrainedOffset;
}
FToolWidget_DragBoxPosition SDraggableBoxOverlay::GetDragBoxPosition() const
{
return FToolWidget_DragBoxPosition{ GetBoxAlignmentOffset(), HorizontalAlignment, VerticalAlignment };
}
void SDraggableBoxOverlay::RestoreFromDragBoxPosition(const FToolWidget_DragBoxPosition& InWidgetPosition)
{
SetBoxHorizontalAlignment(InWidgetPosition.HAlign);
SetBoxVerticalAlignment(InWidgetPosition.VAlign);
// Do not recompute the anchors. Suppose the viewport is now much smaller than it was when InWidgetPosition was saved.
// If the user now increases the size of the viewport, the widget should stay anchored to the same corner as when it was saved.
constexpr bool bRecomputeAnchors = false;
SetBoxAlignmentOffset(InWidgetPosition.RelativeOffset, bRecomputeAnchors);
}
}