EM_Task/UnrealEd/Private/DragAndDrop/AssetDragDropOp.cpp
Boshuang Zhao 5144a49c9b add
2026-02-13 16:18:33 +08:00

235 lines
8.2 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "DragAndDrop/AssetDragDropOp.h"
#include "Engine/Level.h"
#include "ActorFactories/ActorFactory.h"
#include "GameFramework/Actor.h"
#include "Widgets/SOverlay.h"
#include "Widgets/Layout/SBox.h"
#include "AssetThumbnail.h"
#include "ClassIconFinder.h"
TSharedRef<FAssetDragDropOp> FAssetDragDropOp::New(const FAssetData& InAssetData, UActorFactory* ActorFactory)
{
TArray<FAssetData> AssetDataArray;
AssetDataArray.Emplace(InAssetData);
return New(MoveTemp(AssetDataArray), TArray<FString>(), ActorFactory);
}
TSharedRef<FAssetDragDropOp> FAssetDragDropOp::New(TArray<FAssetData> InAssetData, UActorFactory* ActorFactory)
{
return New(MoveTemp(InAssetData), TArray<FString>(), ActorFactory);
}
TSharedRef<FAssetDragDropOp> FAssetDragDropOp::New(FString InAssetPath)
{
TArray<FString> AssetPathsArray;
AssetPathsArray.Emplace(MoveTemp(InAssetPath));
return New(TArray<FAssetData>(), MoveTemp(AssetPathsArray), nullptr);
}
TSharedRef<FAssetDragDropOp> FAssetDragDropOp::New(TArray<FString> InAssetPaths)
{
return New(TArray<FAssetData>(), MoveTemp(InAssetPaths), nullptr);
}
TSharedRef<FAssetDragDropOp> FAssetDragDropOp::New(TArray<FAssetData> InAssetData, TArray<FString> InAssetPaths, UActorFactory* ActorFactory)
{
TSharedRef<FAssetDragDropOp> Operation = MakeShared<FAssetDragDropOp>();
Operation->Init(MoveTemp(InAssetData), MoveTemp(InAssetPaths), ActorFactory);
Operation->Construct();
return Operation;
}
FAssetDragDropOp::~FAssetDragDropOp()
{
ThumbnailPool.Reset();
}
TSharedPtr<SWidget> FAssetDragDropOp::GetDefaultDecorator() const
{
const int32 TotalCount = GetTotalCount();
TSharedPtr<SWidget> ThumbnailWidget;
if (AssetThumbnail.IsValid())
{
ThumbnailWidget = AssetThumbnail->MakeThumbnailWidget();
}
else if (HasFolders())
{
ThumbnailWidget =
SNew(SOverlay)
+ SOverlay::Slot()
[SNew(SImage)
.Image(FEditorStyle::GetBrush("ContentBrowser.ListViewFolderIcon.Base"))
.ColorAndOpacity(FLinearColor::Gray)]
+ SOverlay::Slot()
[SNew(SImage)
.Image(FEditorStyle::GetBrush("ContentBrowser.ListViewFolderIcon.Mask"))];
}
else
{
ThumbnailWidget =
SNew(SImage)
.Image(FEditorStyle::GetDefaultBrush());
}
const FSlateBrush* SubTypeBrush = FEditorStyle::GetDefaultBrush();
FLinearColor SubTypeColor = FLinearColor::White;
if (AssetThumbnail.IsValid() && HasFolders())
{
SubTypeBrush = FEditorStyle::GetBrush("ContentBrowser.AssetTreeFolderClosed");
SubTypeColor = FLinearColor::Gray;
}
else if (ActorFactory.IsValid() && HasFiles())
{
AActor* DefaultActor = ActorFactory->GetDefaultActor(AssetData[0]);
SubTypeBrush = FClassIconFinder::FindIconForActor(DefaultActor);
}
return SNew(SBorder)
.BorderImage(FEditorStyle::GetBrush("ContentBrowser.AssetDragDropTooltipBackground"))
.Content()
[SNew(SHorizontalBox)
// Left slot is for the thumbnail
+ SHorizontalBox::Slot()
.AutoWidth()
.HAlign(HAlign_Left)
[SNew(SBox)
.WidthOverride(ThumbnailSize)
.HeightOverride(ThumbnailSize)
.Content()
[SNew(SOverlay)
+ SOverlay::Slot()
[ThumbnailWidget.ToSharedRef()]
+ SOverlay::Slot()
.HAlign(HAlign_Center)
.VAlign(VAlign_Top)
.Padding(FMargin(0, 4, 0, 0))
[SNew(SBorder)
.BorderImage(FEditorStyle::GetBrush("Menu.Background"))
.Visibility(TotalCount > 1 ? EVisibility::Visible : EVisibility::Collapsed)
.Content()
[SNew(STextBlock)
.Text(FText::AsNumber(TotalCount))]]
+ SOverlay::Slot()
.HAlign(HAlign_Right)
.VAlign(VAlign_Bottom)
.Padding(FMargin(4, 4))
[SNew(SImage)
.Image(SubTypeBrush)
.Visibility(SubTypeBrush != FEditorStyle::GetDefaultBrush() ? EVisibility::Visible : EVisibility::Collapsed)
.ColorAndOpacity(SubTypeColor)]]]
// Right slot is for optional tooltip
+ SHorizontalBox::Slot()
.AutoWidth()
.VAlign(VAlign_Center)
[SNew(SBox)
.MinDesiredWidth(80)
.Content()
[SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
.AutoWidth()
.Padding(3.0f)
.VAlign(VAlign_Center)
[SNew(SImage)
.Image(this, &FAssetDragDropOp::GetIcon)]
+ SHorizontalBox::Slot()
.AutoWidth()
.Padding(0, 0, 3, 0)
.VAlign(VAlign_Center)
[SNew(STextBlock)
.Text(this, &FAssetDragDropOp::GetDecoratorText)]]]];
}
FText FAssetDragDropOp::GetDecoratorText() const
{
if (CurrentHoverText.IsEmpty())
{
const int32 TotalCount = GetTotalCount();
if (TotalCount > 0)
{
const FText FirstItemText = GetFirstItemText();
return (TotalCount == 1) ? FirstItemText : FText::Format(NSLOCTEXT("ContentBrowser", "AssetDragDropOpDescriptionMulti", "'{0}' and {1} {1}|plural(one=other,other=others)"), FirstItemText, TotalCount - 1);
}
}
return CurrentHoverText;
}
void FAssetDragDropOp::Init(TArray<FAssetData> InAssetData, TArray<FString> InAssetPaths, UActorFactory* InActorFactory)
{
MouseCursor = EMouseCursor::GrabHandClosed;
ThumbnailSize = 64;
AssetData = MoveTemp(InAssetData);
AssetPaths = MoveTemp(InAssetPaths);
ActorFactory = InActorFactory;
// Load all assets first so that there is no loading going on while attempting to drag
// Can cause unsafe frame reentry
for (FAssetData& Data: AssetData)
{
Data.GetAsset();
}
InitThumbnail();
}
void FAssetDragDropOp::InitThumbnail()
{
if (AssetData.Num() > 0 && ThumbnailSize > 0)
{
// Create a thumbnail pool to hold the single thumbnail rendered
ThumbnailPool = MakeShared<FAssetThumbnailPool>(1, /*InAreRealTileThumbnailsAllowed=*/false);
// Create the thumbnail handle
AssetThumbnail = MakeShared<FAssetThumbnail>(AssetData[0], ThumbnailSize, ThumbnailSize, ThumbnailPool);
// Request the texture then tick the pool once to render the thumbnail
AssetThumbnail->GetViewportRenderTargetTexture();
ThumbnailPool->Tick(0);
}
}
bool FAssetDragDropOp::HasFiles() const
{
return AssetData.Num() > 0;
}
bool FAssetDragDropOp::HasFolders() const
{
return AssetPaths.Num() > 0;
}
int32 FAssetDragDropOp::GetTotalCount() const
{
return AssetData.Num() + AssetPaths.Num();
}
FText FAssetDragDropOp::GetFirstItemText() const
{
if (AssetData.Num() > 0)
{
return FText::FromName(AssetData[0].AssetName);
}
if (AssetPaths.Num() > 0)
{
return FText::FromString(AssetPaths[0]);
}
return FText::GetEmpty();
}