Files
UnrealEngineUWP/Engine/Source/Editor/EditorWidgets/Private/SDropTarget.cpp
mateo egey 9de144b40f Added cache functionality to SDropTarget for very expensive AllowDrop operations.
Turned off by default.
By default, OnAllowDrop is called every frame, which is user bound. Setting "bUseAllowDropCache" to true will cache off AllowDrop the first time it is called.
The cache is cleared whenever a drag & drop operation starts.

#jira UE-176808
#rb Patrick.Boutot
#preflight 63eb8a3eb91ae11c1c33ebc0

[CL 24214083 by mateo egey in ue5-main branch]
2023-02-14 12:11:50 -05:00

253 lines
6.6 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "SDropTarget.h"
#include "Framework/Application/SlateApplication.h"
#include "Layout/Children.h"
#include "Layout/Clipping.h"
#include "Layout/Geometry.h"
#include "Math/Vector2D.h"
#include "Rendering/DrawElements.h"
#include "Rendering/RenderingCommon.h"
#include "SlotBase.h"
#include "Styling/SlateBrush.h"
#include "Widgets/Layout/SBorder.h"
#include "Widgets/SOverlay.h"
class FSlateRect;
class FWidgetStyle;
#define LOCTEXT_NAMESPACE "EditorWidgets"
void SDropTarget::Construct(const FArguments& InArgs)
{
DroppedEvent = InArgs._OnDropped;
AllowDropEvent = InArgs._OnAllowDrop;
IsRecognizedEvent = InArgs._OnIsRecognized;
OnDragEnterEvent = InArgs._OnDragEnter;
OnDragLeaveEvent = InArgs._OnDragLeave;
bOnlyRecognizeOnDragEnter = InArgs._bOnlyRecognizeOnDragEnter;
bUseAllowDropCache = InArgs._bUseAllowDropCache;
bIsDragEventRecognized = false;
bAllowDrop = false;
bIsDragOver = false;
ValidColor = InArgs._ValidColor;
InvalidColor = InArgs._InvalidColor;
VerticalImage = InArgs._VerticalImage;
HorizontalImage = InArgs._HorizontalImage;
// if we want to use the cache, we need to detect whether to clear the cache on tick
SetCanTick(bUseAllowDropCache);
ChildSlot
[
SNew(SOverlay)
.Clipping(EWidgetClipping::ClipToBounds)
+ SOverlay::Slot()
[
InArgs._Content.Widget
]
+ SOverlay::Slot()
[
SNew(SBorder)
.Visibility(this, &SDropTarget::GetDragOverlayVisibility)
.BorderImage(InArgs._BackgroundImage)
.BorderBackgroundColor(this, &SDropTarget::GetBackgroundBrightness)
]
];
}
FSlateColor SDropTarget::GetBackgroundBrightness() const
{
return bAllowDrop ? ValidColor : InvalidColor;
}
EVisibility SDropTarget::GetDragOverlayVisibility() const
{
if ( FSlateApplication::Get().IsDragDropping() )
{
bool bCheckForAllowDrop = true;
if(bOnlyRecognizeOnDragEnter.Get() && !bIsDragOver)
{
bCheckForAllowDrop = false;
}
if(bCheckForAllowDrop)
{
if(AllowDrop(FSlateApplication::Get().GetDragDroppingContent()) || (bIsDragOver && bIsDragEventRecognized))
{
return EVisibility::HitTestInvisible;
}
}
}
return EVisibility::Hidden;
}
FReply SDropTarget::OnDragOver(const FGeometry& MyGeometry, const FDragDropEvent& DragDropEvent)
{
// Handle the reply if we are allowed to drop, otherwise do not handle it.
return AllowDrop(DragDropEvent.GetOperation()) ? FReply::Handled() : FReply::Unhandled();
}
bool SDropTarget::AllowDrop(TSharedPtr<FDragDropOperation> DragDropOperation) const
{
if(bUseAllowDropCache && AllowDropCache.IsSet())
{
bAllowDrop = AllowDropCache.GetValue();
}
else
{
bAllowDrop = OnAllowDrop(DragDropOperation);
if(bUseAllowDropCache)
{
AllowDropCache = bAllowDrop;
}
}
bIsDragEventRecognized = OnIsRecognized(DragDropOperation) || bAllowDrop;
return bAllowDrop;
}
bool SDropTarget::OnAllowDrop(TSharedPtr<FDragDropOperation> DragDropOperation) const
{
if ( AllowDropEvent.IsBound() )
{
return AllowDropEvent.Execute(DragDropOperation);
}
return false;
}
bool SDropTarget::OnIsRecognized(TSharedPtr<FDragDropOperation> DragDropOperation) const
{
if ( IsRecognizedEvent.IsBound() )
{
return IsRecognizedEvent.Execute(DragDropOperation);
}
return false;
}
void SDropTarget::Tick(const FGeometry& AllottedGeometry, const double InCurrentTime, const float InDeltaTime)
{
if(bUseAllowDropCache)
{
bWasDragDroppingLastFrame = bIsDragDropping;
bIsDragDropping = FSlateApplication::Get().IsDragDropping();
if(bIsDragDropping && !bWasDragDroppingLastFrame)
{
ClearAllowDropCache();
}
}
}
FReply SDropTarget::OnDrop(const FGeometry& MyGeometry, const FDragDropEvent& DragDropEvent)
{
const bool bCurrentbAllowDrop = bAllowDrop;
// We've dropped an asset so we are no longer being dragged over
bIsDragEventRecognized = false;
bIsDragOver = false;
bAllowDrop = false;
// if we allow drop, call a delegate to handle the drop
if ( bCurrentbAllowDrop )
{
if ( DroppedEvent.IsBound() )
{
return DroppedEvent.Execute(MyGeometry, DragDropEvent);
}
return FReply::Handled();
}
return FReply::Unhandled();
}
void SDropTarget::OnDragEnter(const FGeometry& MyGeometry, const FDragDropEvent& DragDropEvent)
{
// initially we dont recognize this event
bIsDragEventRecognized = false;
bIsDragOver = true;
OnDragEnterEvent.ExecuteIfBound(DragDropEvent);
}
void SDropTarget::OnDragLeave(const FDragDropEvent& DragDropEvent)
{
// No longer being dragged over
bIsDragEventRecognized = false;
// Disallow dropping if not dragged over.
bAllowDrop = false;
bIsDragOver = false;
OnDragLeaveEvent.ExecuteIfBound(DragDropEvent);
}
int32 SDropTarget::OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyCullingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled) const
{
LayerId = SCompoundWidget::OnPaint(Args, AllottedGeometry, MyCullingRect, OutDrawElements, LayerId, InWidgetStyle, bParentEnabled);
if ( GetDragOverlayVisibility().IsVisible() )
{
if ( bIsDragEventRecognized )
{
FSlateColor DashColor = bAllowDrop ? ValidColor : InvalidColor;
int32 DashLayer = LayerId + 1;
const float Inset = 3.0f;
// Top
FSlateDrawElement::MakeBox(
OutDrawElements,
DashLayer,
AllottedGeometry.ToPaintGeometry(FVector2f(AllottedGeometry.GetLocalSize().X-Inset*2, HorizontalImage->ImageSize.Y), FSlateLayoutTransform(FVector2f(Inset, 0))),
HorizontalImage,
ESlateDrawEffect::None,
DashColor.GetColor(InWidgetStyle));
// Bottom
FSlateDrawElement::MakeBox(
OutDrawElements,
DashLayer,
AllottedGeometry.ToPaintGeometry(FVector2f(AllottedGeometry.Size.X-Inset * 2, HorizontalImage->ImageSize.Y), FSlateLayoutTransform(FVector2f(Inset, AllottedGeometry.GetLocalSize().Y - HorizontalImage->ImageSize.Y))),
HorizontalImage,
ESlateDrawEffect::None,
DashColor.GetColor(InWidgetStyle));
// Left
FSlateDrawElement::MakeBox(
OutDrawElements,
DashLayer,
AllottedGeometry.ToPaintGeometry(FVector2f(VerticalImage->ImageSize.X, AllottedGeometry.GetLocalSize().Y-Inset * 2), FSlateLayoutTransform(FVector2f(0, Inset))),
VerticalImage,
ESlateDrawEffect::None,
DashColor.GetColor(InWidgetStyle));
// Right
FSlateDrawElement::MakeBox(
OutDrawElements,
DashLayer,
AllottedGeometry.ToPaintGeometry(FVector2f(VerticalImage->ImageSize.X, AllottedGeometry.GetLocalSize().Y-Inset * 2), FSlateLayoutTransform(FVector2f(AllottedGeometry.GetLocalSize().X - VerticalImage->ImageSize.X, Inset))),
VerticalImage,
ESlateDrawEffect::None,
DashColor.GetColor(InWidgetStyle));
return DashLayer;
}
}
return LayerId;
}
#undef LOCTEXT_NAMESPACE