| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167 | // Copyright 2017-2021 marynate. All Rights Reserved.#include "ExtAssetViewWidgets.h"#include "ExtAssetThumbnail.h"#include "ExtContentBrowser.h"#include "ExtContentBrowserSettings.h"#include "ExtContentBrowserSingleton.h"#include "ExtAssetViewTypes.h"#include "DragDropHandler.h"#include "ExtContentBrowserUtils.h"// Engine - Editor#include "UObject/UnrealType.h"#include "ObjectTools.h"#include "Engine/GameViewportClient.h"#include "Engine/Texture2D.h"#include "Materials/Material.h"#include "EditorFramework/AssetImportData.h"#include "Internationalization/BreakIterator.h"#include "Misc/EngineBuildSettings.h"// Asset#include "AssetRegistry/ARFilter.h"#include "AssetRegistry/AssetRegistryModule.h"#include "IAssetTools.h"#include "AssetToolsModule.h"#include "AutoReimport/AssetSourceFilenameCache.h"#include "DragAndDrop/AssetDragDropOp.h"// Slate#include "SlateOptMacros.h"#include "Framework/Application/SlateApplication.h"#include "Widgets/SOverlay.h"#include "Widgets/Images/SImage.h"#include "Widgets/Text/SInlineEditableTextBlock.h"#include "Widgets/Images/SLayeredImage.h"#include "ISourceControlProvider.h"#include "ISourceControlModule.h"#include "SourceControlHelpers.h"// Collection#include "CollectionManagerTypes.h"#include "ICollectionManager.h"#include "CollectionManagerModule.h"//#include "ActorFolder.h"#define LOCTEXT_NAMESPACE "ExtContentBrowser"///////////////////////////////// FAssetViewModeUtils///////////////////////////////FReply FAssetViewModeUtils::OnViewModeKeyDown( const TSet< TSharedPtr<FExtAssetViewItem> >& SelectedItems, const FKeyEvent& InKeyEvent ){	// All asset views use Ctrl-C to copy references to assets	if ( InKeyEvent.IsControlDown() && InKeyEvent.GetCharacter() == 'C' 		&& !InKeyEvent.IsShiftDown() && !InKeyEvent.IsAltDown()		)	{		FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked<FAssetRegistryModule>(TEXT("AssetRegistry"));		TArray<FExtAssetData> SelectedAssets;		for ( auto ItemIt = SelectedItems.CreateConstIterator(); ItemIt; ++ItemIt)		{			const TSharedPtr<FExtAssetViewItem>& Item = *ItemIt;			if(Item.IsValid())			{				if(Item->GetType() == EExtAssetItemType::Folder)				{					// we need to recurse & copy references to all folder contents					FARFilter Filter;					Filter.PackagePaths.Add(*StaticCastSharedPtr<FExtAssetViewFolder>(Item)->FolderPath);					// Add assets found in the asset registry					//AssetRegistryModule.Get().GetAssets(Filter, SelectedAssets);				}				else				{					SelectedAssets.Add(StaticCastSharedPtr<FExtAssetViewAsset>(Item)->Data);				}			}		}		//ContentBrowserUtils::CopyAssetReferencesToClipboard(SelectedAssets);		return FReply::Handled();	}	return FReply::Unhandled();}///////////////////////////////// FAssetViewModeUtils///////////////////////////////TSharedRef<SWidget> FExtAssetViewItemHelper::CreateListItemContents(SExtAssetListItem* const InListItem, const TSharedRef<SWidget>& InThumbnail, FName& OutItemShadowBorder){	return CreateListTileItemContents(InListItem, InThumbnail, OutItemShadowBorder);}TSharedRef<SWidget> FExtAssetViewItemHelper::CreateTileItemContents(SExtAssetTileItem* const InTileItem, const TSharedRef<SWidget>& InThumbnail, FName& OutItemShadowBorder){	return CreateListTileItemContents(InTileItem, InThumbnail, OutItemShadowBorder);}template <typename T>TSharedRef<SWidget> FExtAssetViewItemHelper::CreateListTileItemContents(T* const InTileOrListItem, const TSharedRef<SWidget>& InThumbnail, FName& OutItemShadowBorder){	TSharedRef<SOverlay> ItemContentsOverlay = SNew(SOverlay);	OutItemShadowBorder = FName("ContentBrowser.AssetTileItem.DropShadow");	if (InTileOrListItem->IsFolder())	{		// TODO: Allow items to customize their widget		TSharedPtr<FExtAssetViewFolder> AssetFolderItem = StaticCastSharedPtr<FExtAssetViewFolder>(InTileOrListItem->AssetItem);		const FSlateBrush* FolderBaseImage = FAppStyle::GetBrush("ContentBrowser.ListViewFolderIcon");		// Folder base		ItemContentsOverlay->AddSlot()		.Padding(FMargin(5))		[			SNew(SBorder)			.BorderImage(FAppStyle::Get().GetBrush("ContentBrowser.FolderItem.DropShadow"))			.Padding(FMargin(0,0,2.0f,2.0f))			[				SNew(SImage)				.Image(FolderBaseImage)				.ColorAndOpacity(InTileOrListItem, &T::GetAssetColor)			]		];	}	else	{		// The actual thumbnail		ItemContentsOverlay->AddSlot()		[			InThumbnail		];		// Source control state		ItemContentsOverlay->AddSlot()		.HAlign(HAlign_Right)		.VAlign(VAlign_Top)		.Padding(FMargin(0.0f, 3.0f, 3.0f, 0.0f))		[			SNew(SBox)			.WidthOverride(InTileOrListItem, &T::GetStateIconImageSize)			.HeightOverride(InTileOrListItem, &T::GetStateIconImageSize)			[				InTileOrListItem->GenerateSourceControlIconWidget()			]		];		// Extra external state hook		ItemContentsOverlay->AddSlot()		.HAlign(HAlign_Left)		.VAlign(VAlign_Top)		[			SNew(SBox)			.MaxDesiredWidth(InTileOrListItem, &T::GetExtraStateIconMaxWidth)			.MaxDesiredHeight(InTileOrListItem, &T::GetStateIconImageSize)			[				InTileOrListItem->GenerateExtraStateIconWidget(TAttribute<float>(InTileOrListItem, &T::GetExtraStateIconWidth))			]		];		// Dirty state		ItemContentsOverlay->AddSlot()		.HAlign(HAlign_Left)		.VAlign(VAlign_Bottom)		[			SNew(SBox)			.MaxDesiredWidth(InTileOrListItem, &T::GetStateIconImageSize)			.MaxDesiredHeight(InTileOrListItem, &T::GetStateIconImageSize)			[				SNew(SImage)				.Image(InTileOrListItem, &T::GetDirtyImage)			]		];	}	return ItemContentsOverlay;}///////////////////////////////// Asset view item tool tip///////////////////////////////class SExtAssetViewItemToolTip : public SToolTip{public:	SLATE_BEGIN_ARGS(SExtAssetViewItemToolTip)		: _AssetViewItem()	{ }		SLATE_ARGUMENT(TSharedPtr<SExtAssetViewItem>, AssetViewItem)	SLATE_END_ARGS()	void Construct(const FArguments& InArgs)	{		AssetViewItem = InArgs._AssetViewItem;		SToolTip::Construct(			SToolTip::FArguments()			.TextMargin(1.0f)			.BorderImage(FAppStyle::GetBrush("ContentBrowser.TileViewTooltip.ToolTipBorder"))			);	}	// IToolTip interface	virtual bool IsEmpty() const override	{		return !AssetViewItem.IsValid();	}	virtual void OnOpening() override	{		TSharedPtr<SExtAssetViewItem> AssetViewItemPin = AssetViewItem.Pin();		if (AssetViewItemPin.IsValid())		{			SetContentWidget(AssetViewItemPin->CreateToolTipWidget());		}	}	virtual void OnClosed() override	{		SetContentWidget(SNullWidget::NullWidget);	}private:	TWeakPtr<SExtAssetViewItem> AssetViewItem;};///////////////////////////////// Asset view modes///////////////////////////////FReply SExtAssetTileView::OnKeyDown( const FGeometry& InGeometry, const FKeyEvent& InKeyEvent ){	FReply Reply = FAssetViewModeUtils::OnViewModeKeyDown(SelectedItems, InKeyEvent);	if ( Reply.IsEventHandled() )	{		return Reply;	}	else	{		return STileView<TSharedPtr<FExtAssetViewItem>>::OnKeyDown(InGeometry, InKeyEvent);	}}void SExtAssetTileView::Tick(const FGeometry& AllottedGeometry, const double InCurrentTime, const float InDeltaTime){	// Regreshing an asset view is an intensive task. Do not do this while a user	// is dragging arround content for maximum responsiveness.	// Also prevents a re-entrancy crash caused by potentially complex thumbnail generators.	if (!FSlateApplication::Get().IsDragDropping())	{		STileView<TSharedPtr<FExtAssetViewItem>>::Tick(AllottedGeometry, InCurrentTime, InDeltaTime);	}}bool SExtAssetTileView::HasWidgetForAsset(const FName& AssetPathName){	for (const TSharedPtr<FExtAssetViewItem>& Item : WidgetGenerator.ItemsWithGeneratedWidgets)	{		if (Item.IsValid() && Item->GetType() == EExtAssetItemType::Normal)		{			const FName& ObjectPath = StaticCastSharedPtr<FExtAssetViewAsset>(Item)->Data.ObjectPath;			if (ObjectPath == AssetPathName)			{				return true;			}		}	}	return false;}FReply SExtAssetListView::OnKeyDown(const FGeometry& InGeometry, const FKeyEvent& InKeyEvent){	FReply Reply = FAssetViewModeUtils::OnViewModeKeyDown(SelectedItems, InKeyEvent);	if ( Reply.IsEventHandled() )	{		return Reply;	}	else	{		return SListView<TSharedPtr<FExtAssetViewItem>>::OnKeyDown(InGeometry, InKeyEvent);	}}void SExtAssetListView::Tick(const FGeometry& AllottedGeometry, const double InCurrentTime, const float InDeltaTime){	// Regreshing an asset view is an intensive task. Do not do this while a user	// is dragging arround content for maximum responsiveness.	// Also prevents a re-entrancy crash caused by potentially complex thumbnail generators.	if (!FSlateApplication::Get().IsDragDropping())	{		SListView<TSharedPtr<FExtAssetViewItem>>::Tick(AllottedGeometry, InCurrentTime, InDeltaTime);	}}bool SExtAssetListView::HasWidgetForAsset(const FName& AssetPathName){	for (const TSharedPtr<FExtAssetViewItem>& Item : WidgetGenerator.ItemsWithGeneratedWidgets)	{		if (Item.IsValid() && Item->GetType() == EExtAssetItemType::Normal)		{			const FName& ObjectPath = StaticCastSharedPtr<FExtAssetViewAsset>(Item)->Data.ObjectPath;			if (ObjectPath == AssetPathName)			{				return true;			}		}	}	return false;}FReply SExtAssetColumnView::OnKeyDown(const FGeometry& InGeometry, const FKeyEvent& InKeyEvent){	FReply Reply = FAssetViewModeUtils::OnViewModeKeyDown(SelectedItems, InKeyEvent);	if ( Reply.IsEventHandled() )	{		return Reply;	}	else	{		return SListView<TSharedPtr<FExtAssetViewItem>>::OnKeyDown(InGeometry, InKeyEvent);	}}void SExtAssetColumnView::Tick(const FGeometry& AllottedGeometry, const double InCurrentTime, const float InDeltaTime){	// Regreshing an asset view is an intensive task. Do not do this while a user	// is dragging arround content for maximum responsiveness.	// Also prevents a re-entrancy crash caused by potentially complex thumbnail generators.	if (!FSlateApplication::Get().IsDragDropping())	{		return SListView<TSharedPtr<FExtAssetViewItem>>::Tick(AllottedGeometry, InCurrentTime, InDeltaTime);	}}///////////////////////////////// SExtAssetViewItem///////////////////////////////SExtAssetViewItem::~SExtAssetViewItem(){	if (AssetItem.IsValid())	{		AssetItem->OnAssetDataChanged.RemoveAll(this);	}	OnItemDestroyed.ExecuteIfBound(AssetItem);	if (!GExitPurge)	{		const bool bIsGarbageCollectingOnGameThread = (IsInGameThread() && IsGarbageCollecting());		if (!bIsGarbageCollectingOnGameThread)		{			// This hack is here to make abnormal shutdowns less frequent.  Crashes here are the result UI's being shut down as a result of GC at edtior shutdown.  This code attemps to call FindObject which is not allowed during GC.			SetForceMipLevelsToBeResident(false);		}	}}void SExtAssetViewItem::Construct( const FArguments& InArgs ){	AssetItem = InArgs._AssetItem;	OnRenameBegin = InArgs._OnRenameBegin;	OnRenameCommit = InArgs._OnRenameCommit;	OnVerifyRenameCommit = InArgs._OnVerifyRenameCommit;	OnItemDestroyed = InArgs._OnItemDestroyed;	ShouldAllowToolTip = InArgs._ShouldAllowToolTip;	ThumbnailEditMode = InArgs._ThumbnailEditMode;	HighlightText = InArgs._HighlightText;	OnAssetsOrPathsDragDropped = InArgs._OnAssetsOrPathsDragDropped;	OnFilesDragDropped = InArgs._OnFilesDragDropped;	OnIsAssetValidForCustomToolTip = InArgs._OnIsAssetValidForCustomToolTip;	OnGetCustomAssetToolTip = InArgs._OnGetCustomAssetToolTip;	OnVisualizeAssetToolTip = InArgs._OnVisualizeAssetToolTip;	OnAssetToolTipClosing = InArgs._OnAssetToolTipClosing;	bDraggedOver = false;	bPackageDirty = false;	OnAssetDataChanged();	AssetItem->OnAssetDataChanged.AddSP(this, &SExtAssetViewItem::OnAssetDataChanged);	AssetDirtyBrush = FAppStyle::GetBrush("ContentBrowser.ContentDirty");	// Set our tooltip - this will refresh each time it's opened to make sure it's up-to-date	SetToolTip(SNew(SExtAssetViewItemToolTip).AssetViewItem(SharedThis(this)));	SourceControlStateDelay = 0.0f;	bSourceControlStateRequested = false;	ISourceControlModule::Get().RegisterProviderChanged(FSourceControlProviderChanged::FDelegate::CreateSP(this, &SExtAssetViewItem::HandleSourceControlProviderChanged));	SourceControlStateChangedDelegateHandle = ISourceControlModule::Get().GetProvider().RegisterSourceControlStateChanged_Handle(FSourceControlStateChanged::FDelegate::CreateSP(this, &SExtAssetViewItem::HandleSourceControlStateChanged));	// Source control state may have already been cached, make sure the control is in sync with 	// cached state as the delegate is not going to be invoked again until source control state 	// changes. This will be necessary any time the widget is destroyed and recreated after source 	// control state has been cached; for instance when the widget is killed via FWidgetGenerator::OnEndGenerationPass 	// or a view is refreshed due to user filtering/navigating):	HandleSourceControlStateChanged();}void SExtAssetViewItem::Tick( const FGeometry& AllottedGeometry, const double InCurrentTime, const float InDeltaTime ){	const float PrevSizeX = LastGeometry.Size.X;	LastGeometry = AllottedGeometry;	// Set cached wrap text width based on new "LastGeometry" value. 	// We set this only when changed because binding a delegate to text wrapping attributes is expensive	if( PrevSizeX != AllottedGeometry.Size.X && InlineRenameWidget.IsValid() )	{		InlineRenameWidget->SetWrapTextAt( GetNameTextWrapWidth() );	}	UpdatePackageDirtyState();	UpdateSourceControlState((float)InDeltaTime);}TSharedPtr<IToolTip> SExtAssetViewItem::GetToolTip(){	return ShouldAllowToolTip.Get() ? SCompoundWidget::GetToolTip() : NULL;}bool SExtAssetViewItem::ValidateDragDrop( const FGeometry& MyGeometry, const FDragDropEvent& DragDropEvent, bool& OutIsKnownDragOperation ) const{	OutIsKnownDragOperation = false;	return IsFolder() && DragDropHandler::ValidateDragDropOnAssetFolder(MyGeometry, DragDropEvent, StaticCastSharedPtr<FExtAssetViewFolder>(AssetItem)->FolderPath, OutIsKnownDragOperation);}void SExtAssetViewItem::OnDragEnter( const FGeometry& MyGeometry, const FDragDropEvent& DragDropEvent ){	ValidateDragDrop(MyGeometry, DragDropEvent, bDraggedOver); // updates bDraggedOver}	void SExtAssetViewItem::OnDragLeave( const FDragDropEvent& DragDropEvent ){	if(IsFolder())	{		TSharedPtr<FDragDropOperation> Operation = DragDropEvent.GetOperation();		if (Operation.IsValid())		{			Operation->SetCursorOverride(TOptional<EMouseCursor::Type>());			if (Operation->IsOfType<FAssetDragDropOp>())			{				TSharedPtr<FAssetDragDropOp> DragDropOp = StaticCastSharedPtr<FAssetDragDropOp>(Operation);				DragDropOp->ResetToDefaultToolTip();			}		}	}	bDraggedOver = false;}FReply SExtAssetViewItem::OnDragOver( const FGeometry& MyGeometry, const FDragDropEvent& DragDropEvent ){	ValidateDragDrop(MyGeometry, DragDropEvent, bDraggedOver); // updates bDraggedOver	return (bDraggedOver) ? FReply::Handled() : FReply::Unhandled();}FReply SExtAssetViewItem::OnDrop( const FGeometry& MyGeometry, const FDragDropEvent& DragDropEvent ){	if (ValidateDragDrop(MyGeometry, DragDropEvent, bDraggedOver)) // updates bDraggedOver	{		bDraggedOver = false;		check(AssetItem->GetType() == EExtAssetItemType::Folder);		TSharedPtr<FDragDropOperation> Operation = DragDropEvent.GetOperation();		if (!Operation.IsValid())		{			return FReply::Unhandled();		}		if (Operation->IsOfType<FExternalDragOperation>())		{			TSharedPtr<FExternalDragOperation> DragDropOp = StaticCastSharedPtr<FExternalDragOperation>(Operation);			OnFilesDragDropped.ExecuteIfBound(DragDropOp->GetFiles(), StaticCastSharedPtr<FExtAssetViewFolder>(AssetItem)->FolderPath);			return FReply::Handled();		}				if (Operation->IsOfType<FAssetDragDropOp>())		{			TSharedPtr<FAssetDragDropOp> DragDropOp = StaticCastSharedPtr<FAssetDragDropOp>(Operation);			OnAssetsOrPathsDragDropped.ExecuteIfBound(DragDropOp->GetAssets(), DragDropOp->GetAssetPaths(), StaticCastSharedPtr<FExtAssetViewFolder>(AssetItem)->FolderPath);			return FReply::Handled();		}	}	if (bDraggedOver)	{		// We were able to handle this operation, but could not due to another error - still report this drop as handled so it doesn't fall through to other widgets		bDraggedOver = false;		return FReply::Handled();	}	return FReply::Unhandled();}bool SExtAssetViewItem::IsNameReadOnly() const{	return true;}void SExtAssetViewItem::HandleBeginNameChange( const FText& OriginalText ){	OnRenameBegin.ExecuteIfBound(AssetItem, OriginalText.ToString(), LastGeometry.GetLayoutBoundingRect());}void SExtAssetViewItem::HandleNameCommitted( const FText& NewText, ETextCommit::Type CommitInfo ){	OnRenameCommit.ExecuteIfBound(AssetItem, NewText.ToString(), LastGeometry.GetLayoutBoundingRect(), CommitInfo);}bool  SExtAssetViewItem::HandleVerifyNameChanged( const FText& NewText, FText& OutErrorMessage ){	return !OnVerifyRenameCommit.IsBound() || OnVerifyRenameCommit.Execute(AssetItem, NewText, LastGeometry.GetLayoutBoundingRect(), OutErrorMessage);}void SExtAssetViewItem::OnAssetDataChanged(){	CachePackageName();	AssetPackage = FindObjectSafe<UPackage>(NULL, *CachedPackageName);	UpdatePackageDirtyState();	AssetTypeActions.Reset();	if ( AssetItem->GetType() != EExtAssetItemType::Folder )	{		UClass* AssetClass = FindObject<UClass>(nullptr, *StaticCastSharedPtr<FExtAssetViewAsset>(AssetItem)->Data.AssetClass.ToString());		if (AssetClass)		{			FAssetToolsModule& AssetToolsModule = FModuleManager::LoadModuleChecked<FAssetToolsModule>(TEXT("AssetTools"));			AssetTypeActions = AssetToolsModule.Get().GetAssetTypeActionsForClass(AssetClass).Pin();		}	}	if ( InlineRenameWidget.IsValid() )	{		InlineRenameWidget->SetText( GetNameText() );	}	CacheDisplayTags();}void SExtAssetViewItem::DirtyStateChanged(){}FText SExtAssetViewItem::GetAssetClassText() const{	if (!AssetItem.IsValid())	{		return FText();	}		if (AssetItem->GetType() == EExtAssetItemType::Folder)	{		return LOCTEXT("FolderName", "Folder");	}	if (AssetTypeActions.IsValid())	{		FText Name = AssetTypeActions.Pin()->GetName();		if (!Name.IsEmpty())		{			return Name;		}	}	return FText::FromName(StaticCastSharedPtr<FExtAssetViewAsset>(AssetItem)->Data.AssetClass);}void SExtAssetViewItem::HandleSourceControlProviderChanged(ISourceControlProvider& OldProvider, ISourceControlProvider& NewProvider){	OldProvider.UnregisterSourceControlStateChanged_Handle(SourceControlStateChangedDelegateHandle);	SourceControlStateChangedDelegateHandle = NewProvider.RegisterSourceControlStateChanged_Handle(FSourceControlStateChanged::FDelegate::CreateSP(this, &SExtAssetViewItem::HandleSourceControlStateChanged));		// Reset this so the state will be queried from the new provider on the next Tick	SourceControlStateDelay = 0.0f;	bSourceControlStateRequested = false;		HandleSourceControlStateChanged();}void SExtAssetViewItem::HandleSourceControlStateChanged(){	if ( ISourceControlModule::Get().IsEnabled() && AssetItem.IsValid() && (AssetItem->GetType() == EExtAssetItemType::Normal) && !AssetItem->IsTemporaryItem() && !FPackageName::IsScriptPackage(CachedPackageName) )	{		FSourceControlStatePtr SourceControlState = ISourceControlModule::Get().GetProvider().GetState(CachedPackageFileName, EStateCacheUsage::Use);		if(SourceControlState.IsValid())		{			if (SCCStateWidget.IsValid())			{				SCCStateWidget->SetFromSlateIcon(SourceControlState->GetIcon());			}		}	}}const FSlateBrush* SExtAssetViewItem::GetDirtyImage() const{	return IsDirty() ? AssetDirtyBrush : NULL;}TSharedRef<SWidget> SExtAssetViewItem::GenerateSourceControlIconWidget(){	TSharedRef<SLayeredImage> Image = SNew(SLayeredImage).Image(FStyleDefaults::GetNoBrush());	SCCStateWidget = Image;	return Image;}TSharedRef<SWidget> SExtAssetViewItem::GenerateExtraStateIconWidget(TAttribute<float> InMaxExtraStateIconWidth) const{#if ECB_TODO // Extra icon support	TArray<FOnGenerateAssetViewExtraStateIndicators>& ExtraStateIconGenerators = FModuleManager::GetModuleChecked<FExtContentBrowserModule>(TEXT("ExtContentBrowser")).GetAllAssetViewExtraStateIconGenerators();	if (AssetItem->GetType() != EAssetItemType::Folder && ExtraStateIconGenerators.Num() > 0)	{		FAssetData& AssetData = StaticCastSharedPtr<FAssetViewAsset>(AssetItem)->Data;		TSharedPtr<SHorizontalBox> Content = SNew(SHorizontalBox);		for (const auto& Generator : ExtraStateIconGenerators)		{			if (Generator.IsBound())			{				Content->AddSlot()					.HAlign(HAlign_Left)					.MaxWidth(InMaxExtraStateIconWidth)					[						Generator.Execute(AssetData)					];			}		}		return Content.ToSharedRef();	}#endif	return SNullWidget::NullWidget;}TSharedRef<SWidget> SExtAssetViewItem::GenerateExtraStateTooltipWidget() const{#if ECB_TODO // Extra icon support	TArray<FOnGenerateAssetViewExtraStateIndicators>& ExtraStateTooltipGenerators = FModuleManager::GetModuleChecked<FExtContentBrowserModule>(TEXT("ContentBrowser")).GetAllAssetViewExtraStateTooltipGenerators();	if (AssetItem->GetType() != EAssetItemType::Folder && ExtraStateTooltipGenerators.Num() > 0)	{		FAssetData& AssetData = StaticCastSharedPtr<FAssetViewAsset>(AssetItem)->Data;		TSharedPtr<SVerticalBox> Content = SNew(SVerticalBox);		for (const auto& Generator : ExtraStateTooltipGenerators)		{			if (Generator.IsBound())			{				Content->AddSlot()					[						Generator.Execute(AssetData)					];			}		}		return Content.ToSharedRef();	}#endif	return SNullWidget::NullWidget;}EVisibility SExtAssetViewItem::GetThumbnailEditModeUIVisibility() const{	return !IsFolder() && ThumbnailEditMode.Get() ? EVisibility::Visible : EVisibility::Collapsed;}BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATIONTSharedRef<SWidget> SExtAssetViewItem::CreateToolTipWidget() const{	if ( AssetItem.IsValid() )	{#if ECB_TODO // Custom tooltip		bool bTryCustomAssetToolTip = true;		if (OnIsAssetValidForCustomToolTip.IsBound() && AssetItem->GetType() != EAssetItemType::Folder)		{			FExtAssetData& AssetData = StaticCastSharedPtr<FAssetViewAsset>(AssetItem)->Data;			bTryCustomAssetToolTip = OnIsAssetValidForCustomToolTip.Execute(AssetData);		}		if(bTryCustomAssetToolTip && OnGetCustomAssetToolTip.IsBound() && AssetItem->GetType() != EAssetItemType::Folder)		{			FExtAssetData& AssetData = StaticCastSharedPtr<FAssetViewAsset>(AssetItem)->Data;			return OnGetCustomAssetToolTip.Execute(AssetData);		}		else #endif		if(AssetItem->GetType() != EExtAssetItemType::Folder)		{			const FExtAssetData& AssetData = StaticCastSharedPtr<FExtAssetViewAsset>(AssetItem)->Data;			// The tooltip contains the name, class, path, and asset registry tags			const FText NameText = FText::FromName( AssetData.AssetName );			const FText ClassText = FText::Format( LOCTEXT("ClassName", "({0})"), GetAssetClassText() );			// Create a box to hold every line of info in the body of the tooltip			TSharedRef<SVerticalBox> InfoBox = SNew(SVerticalBox);			// Add File Path			AddToToolTipInfoBox( InfoBox, LOCTEXT("TileViewTooltipPath", "Path"), FText::FromName(AssetData.PackageFilePath), false);			// Saved By Engine Version			AddToToolTipInfoBox(InfoBox, LOCTEXT("TileViewTooltipEngine", "Engine"), FText::FromString(AssetData.SavedByEngineVersion.ToString(EVersionComponent::Patch)), false);#if ECB_DEBUG			// File Version			AddToToolTipInfoBox(InfoBox, LOCTEXT("TileViewTooltipFileVersion", "File Version"), FText::AsNumber(AssetData.FileVersionUE4), false);			AddToToolTipInfoBox(InfoBox, LOCTEXT("TileViewTooltipSavedByEngineDetail", "Saved By Engine"), FText::FromString(AssetData.SavedByEngineVersion.ToString(EVersionComponent::Branch)), false);			AddToToolTipInfoBox(InfoBox, LOCTEXT("TileViewTooltipCompatibleEngineDetail", "Compatible Engine"), FText::FromString(AssetData.CompatibleWithEngineVersion.ToString(EVersionComponent::Branch)), false);			AddToToolTipInfoBox(InfoBox, LOCTEXT("TileViewTooltipPackageName", "PackageName"), FText::FromName(AssetData.PackageName), false);			AddToToolTipInfoBox(InfoBox, LOCTEXT("TileViewTooltipPackagePath", "PackagePath"), FText::FromName(AssetData.PackagePath), false);			AddToToolTipInfoBox(InfoBox, LOCTEXT("TileViewTooltipObjectPath", "ObjectPath"), FText::FromName(AssetData.ObjectPath), false);			AddToToolTipInfoBox(InfoBox, LOCTEXT("TileViewTooltipAssetName", "AssetName"), FText::FromName(AssetData.AssetName), false);			AddToToolTipInfoBox(InfoBox, LOCTEXT("TileViewTooltipAssetClass", "AssetClass"), FText::FromName(AssetData.AssetClass), false);			AddToToolTipInfoBox(InfoBox, LOCTEXT("TileViewTooltipAssetContentRootDir", "AssetContentRootDir"), FText::FromName(AssetData.AssetContentRoot), false);			AddToToolTipInfoBox(InfoBox, LOCTEXT("TileViewTooltipAssetRelativePath", "AssetRelativePath"), FText::FromName(AssetData.AssetRelativePath), false);			AddToToolTipInfoBox(InfoBox, LOCTEXT("TileViewTooltipHasThumbnail", "HasThumbnail"), FText::AsNumber(AssetData.HasThumbnail()), false);			AddToToolTipInfoBox(InfoBox, LOCTEXT("TileViewTooltipNumTagsAndValues", "Num of TagsAndValues"), FText::AsNumber(AssetData.TagsAndValues.Num()), false);			AddToToolTipInfoBox(InfoBox, LOCTEXT("TileViewTooltipHardDependentPackages", "Num of Hard Dependencies"), FText::AsNumber(AssetData.HardDependentPackages.Num()), false);			AddToToolTipInfoBox(InfoBox, LOCTEXT("TileViewTooltipSoftReferencesList", "Num of Soft References"), FText::AsNumber(AssetData.SoftReferencesList.Num()), false);			AddToToolTipInfoBox(InfoBox, LOCTEXT("TileViewTooltipAssetCount", "Num of Assets"), FText::AsNumber(AssetData.AssetCount), false);			AddToToolTipInfoBox(InfoBox, LOCTEXT("TileViewTooltipThumbCount", "Num of Thumbnails"), FText::AsNumber(AssetData.ThumbCount), false);			AddToToolTipInfoBox(InfoBox, LOCTEXT("TileViewTooltipFileSize", "File Size"), FText::AsNumber(AssetData.FileSize), false);#endif			// Add Collections#if ECB_WIP_COLLECTION			{				FCollectionManagerModule& CollectionManagerModule = FCollectionManagerModule::GetModule();				const FString CollectionNames = CollectionManagerModule.Get().GetCollectionsStringForObject(AssetData.ObjectPath, ECollectionShareType::CST_All, ECollectionRecursionFlags::Self, GetDefault<UExtContentBrowserSettings>()->bShowFullCollectionNameInToolTip);				if (!CollectionNames.IsEmpty())				{					AddToToolTipInfoBox(InfoBox, LOCTEXT("AssetToolTipKey_Collections", "Collections"), FText::FromString(CollectionNames), false);				}			}#endif			// Add tags			for (const auto& DisplayTagItem : CachedDisplayTags)			{				AddToToolTipInfoBox(InfoBox, DisplayTagItem.DisplayKey, DisplayTagItem.DisplayValue, DisplayTagItem.bImportant);			}			// Add asset source files			TOptional<FAssetImportInfo> ImportInfo = FExtContentBrowserSingleton::GetAssetRegistry().ExtractAssetImportInfo(AssetData);			if (ImportInfo.IsSet())			{				for (const auto& File : ImportInfo->SourceFiles)				{					FText SourceLabel = LOCTEXT("TileViewTooltipSourceFile", "Source File");					if (File.DisplayLabelName.Len() > 0)					{						SourceLabel = FText::FromString(FText(LOCTEXT("TileViewTooltipSourceFile", "Source File")).ToString() + TEXT(" (") + File.DisplayLabelName + TEXT(")"));					}					AddToToolTipInfoBox( InfoBox, SourceLabel, FText::FromString(File.RelativeFilename), false );				}			}			TSharedRef<SVerticalBox> OverallTooltipVBox = SNew(SVerticalBox);			// Top section (asset name, type, is checked out)			OverallTooltipVBox->AddSlot()				.AutoHeight()				.Padding(0, 0, 0, 4)				[					SNew(SBorder)					.Padding(6)					.BorderImage(FAppStyle::GetBrush("ContentBrowser.TileViewTooltip.ContentBorder"))					[						SNew(SVerticalBox)						+ SVerticalBox::Slot()						.AutoHeight()						[							SNew(SHorizontalBox)							+ SHorizontalBox::Slot()							.AutoWidth()							.VAlign(VAlign_Center)							.Padding(0, 0, 4, 0)							[								SNew(STextBlock)								.Text(NameText)								.Font(FAppStyle::GetFontStyle("ContentBrowser.TileViewTooltip.NameFont"))							]							+ SHorizontalBox::Slot()							.AutoWidth()							.VAlign(VAlign_Center)							[								SNew(STextBlock).Text(ClassText)								.HighlightText(HighlightText)							]						]						+ SVerticalBox::Slot()						.AutoHeight()						[							GenerateExtraStateTooltipWidget()						]					]				];			// Middle section (user description, if present)			FText UserDescription = GetAssetUserDescription();			if (!UserDescription.IsEmpty())			{				OverallTooltipVBox->AddSlot()					.AutoHeight()					.Padding(0, 0, 0, 4)					[						SNew(SBorder)						.Padding(6)						.BorderImage(FAppStyle::GetBrush("ContentBrowser.TileViewTooltip.ContentBorder"))						[							SNew(STextBlock)							.WrapTextAt(300.0f)							.Font(FAppStyle::GetFontStyle("ContentBrowser.TileViewTooltip.AssetUserDescriptionFont"))							.Text(UserDescription)						]					];			}			// Bottom section (asset registry tags)			OverallTooltipVBox->AddSlot()				.AutoHeight()				[					SNew(SBorder)					.Padding(6)					.BorderImage(FAppStyle::GetBrush("ContentBrowser.TileViewTooltip.ContentBorder"))					[						InfoBox					]				];			return SNew(SBorder)				.Padding(6)				.BorderImage( FAppStyle::GetBrush("ContentBrowser.TileViewTooltip.NonContentBorder") )				[					OverallTooltipVBox				];		}		else		{			const FText& FolderName = StaticCastSharedPtr<FExtAssetViewFolder>(AssetItem)->FolderName;			const FString& FolderPath = StaticCastSharedPtr<FExtAssetViewFolder>(AssetItem)->FolderPath;			// Create a box to hold every line of info in the body of the tooltip			TSharedRef<SVerticalBox> InfoBox = SNew(SVerticalBox);			AddToToolTipInfoBox( InfoBox, LOCTEXT("TileViewTooltipPath", "Path"), FText::FromString(FolderPath), false );			return SNew(SBorder)				.Padding(6)				.BorderImage( FAppStyle::GetBrush("ContentBrowser.TileViewTooltip.NonContentBorder") )				[					SNew(SVerticalBox)					+SVerticalBox::Slot()					.AutoHeight()					.Padding(0, 0, 0, 4)					[						SNew(SBorder)						.Padding(6)						.BorderImage( FAppStyle::GetBrush("ContentBrowser.TileViewTooltip.ContentBorder") )						[							SNew(SVerticalBox)							+SVerticalBox::Slot()							.AutoHeight()							[								SNew(SHorizontalBox)								+SHorizontalBox::Slot()								.AutoWidth()								.VAlign(VAlign_Center)								.Padding(0, 0, 4, 0)								[									SNew(STextBlock)									.Text( FolderName )									.Font( FAppStyle::GetFontStyle("ContentBrowser.TileViewTooltip.NameFont") )								]								+SHorizontalBox::Slot()								.AutoWidth()								.VAlign(VAlign_Center)								[									SNew(STextBlock) 									.Text( LOCTEXT("FolderNameBracketed", "(Folder)") )								]							]						]					]					+SVerticalBox::Slot()					.AutoHeight()					[						SNew(SBorder)						.Padding(6)						.BorderImage( FAppStyle::GetBrush("ContentBrowser.TileViewTooltip.ContentBorder") )						[							InfoBox						]					]				];		}	}	else	{		// Return an empty tooltip since the asset item wasn't valid		return SNullWidget::NullWidget;	}}END_SLATE_FUNCTION_BUILD_OPTIMIZATIONFText SExtAssetViewItem::GetAssetUserDescription() const{#if ECB_TODO // Get Asset User Description	if (AssetItem.IsValid() && AssetTypeActions.IsValid())	{		if (AssetItem->GetType() != EAssetItemType::Folder)		{			const FAssetData& AssetData = StaticCastSharedPtr<FAssetViewAsset>(AssetItem)->Data;			return AssetTypeActions.Pin()->GetAssetDescription(AssetData);		}	}#endif	return FText::GetEmpty();}void SExtAssetViewItem::AddToToolTipInfoBox(const TSharedRef<SVerticalBox>& InfoBox, const FText& Key, const FText& Value, bool bImportant) const{	FWidgetStyle ImportantStyle;	ImportantStyle.SetForegroundColor(FLinearColor(1, 0.5, 0, 1));	InfoBox->AddSlot()	.AutoHeight()	.Padding(0, 1)	[		SNew(SHorizontalBox)		+SHorizontalBox::Slot()		.AutoWidth()		.Padding(0, 0, 4, 0)		[			SNew(STextBlock) .Text( FText::Format(LOCTEXT("AssetViewTooltipFormat", "{0}:"), Key ) )			.ColorAndOpacity(bImportant ? ImportantStyle.GetSubduedForegroundColor() : FSlateColor::UseSubduedForeground())		]		+SHorizontalBox::Slot()		.AutoWidth()		[			SNew(STextBlock) .Text( Value )			.ColorAndOpacity(bImportant ? ImportantStyle.GetForegroundColor() : FSlateColor::UseForeground())			.HighlightText((Key.ToString() == TEXT("Path")) ? HighlightText : FText())			.WrapTextAt(700.0f)		]	];}void SExtAssetViewItem::UpdatePackageDirtyState(){	bool bNewIsDirty = false;	// Only update the dirty state for non-temporary asset items that aren't a built in script	if ( AssetItem.IsValid() && !AssetItem->IsTemporaryItem() && AssetItem->GetType() != EExtAssetItemType::Folder && !FPackageName::IsScriptPackage(CachedPackageName) )	{		if ( AssetPackage.IsValid() )		{			bNewIsDirty = AssetPackage->IsDirty();		}	}	if ( bNewIsDirty != bPackageDirty )	{		bPackageDirty = bNewIsDirty;		DirtyStateChanged();	}}bool SExtAssetViewItem::IsDirty() const{	return bPackageDirty;}void SExtAssetViewItem::UpdateSourceControlState(float InDeltaTime){	SourceControlStateDelay += InDeltaTime;	static ISourceControlModule& SourceControlModule = ISourceControlModule::Get();	if ( !bSourceControlStateRequested && SourceControlStateDelay > 1.0f && SourceControlModule.IsEnabled() && AssetItem.IsValid() )	{		// Only update the SCC state for non-temporary asset items that aren't a built in script		if ( !AssetItem->IsTemporaryItem() && AssetItem->GetType() != EExtAssetItemType::Folder && !FPackageName::IsScriptPackage(CachedPackageName) && !FPackageName::IsMemoryPackage(CachedPackageName) && !FPackageName::IsTempPackage(CachedPackageName))		{			// Request the most recent SCC state for this asset			SourceControlModule.QueueStatusUpdate(CachedPackageFileName);		}		bSourceControlStateRequested = true;	}}void SExtAssetViewItem::CachePackageName(){#if ECB_LEGACY	if(AssetItem.IsValid())	{		if(AssetItem->GetType() != EAssetItemType::Folder)		{			CachedPackageName = StaticCastSharedPtr<FAssetViewAsset>(AssetItem)->Data.PackageName.ToString();			CachedPackageFileName = SourceControlHelpers::PackageFilename(CachedPackageName);		}		else		{			CachedPackageName = StaticCastSharedPtr<FAssetViewFolder>(AssetItem)->FolderName.ToString();		}	}#endif}void SExtAssetViewItem::CacheDisplayTags(){	CachedDisplayTags.Reset();	if (AssetItem->GetType() == EExtAssetItemType::Folder)	{		return;	}	const FExtAssetData& AssetData = StaticCastSharedPtr<FExtAssetViewAsset>(AssetItem)->Data;	// Find the asset CDO so we can get the meta-data for the tags	UClass* AssetClass = FindObject<UClass>(nullptr, *AssetData.AssetClass.ToString());	const UObject* AssetCDO = AssetClass ? GetDefault<UObject>(AssetClass) : nullptr;	struct FTagDisplayMetaData	{		FTagDisplayMetaData()			: MetaData()			, Type(UObject::FAssetRegistryTag::TT_Hidden)			, DisplayFlags(UObject::FAssetRegistryTag::TD_None)		{		}		UObject::FAssetRegistryTagMetadata MetaData;		UObject::FAssetRegistryTag::ETagType Type;		uint32 DisplayFlags;	};	bool bHasTagMetaDataMap = false;	// Build up the meta-data needed to correctly process the tags for display	TMap<FName, FTagDisplayMetaData> TagMetaDataMap;	if (AssetCDO)	{		bHasTagMetaDataMap = true;		// Add the internal meta-data		{			TMap<FName, UObject::FAssetRegistryTagMetadata> TmpMetaData;			AssetCDO->GetAssetRegistryTagMetadata(TmpMetaData);			for (const auto& TmpMetaDataPair : TmpMetaData)			{				FTagDisplayMetaData& TagMetaData = TagMetaDataMap.FindOrAdd(TmpMetaDataPair.Key);				TagMetaData.MetaData = TmpMetaDataPair.Value;			}		}		// Add the type and display flags		{			TArray<UObject::FAssetRegistryTag> TmpTags;			if (AssetCDO->GetClass()->IsChildOf(UActorFolder::StaticClass()))			{			}			else			{				AssetCDO->GetAssetRegistryTags(TmpTags);			}			for (const UObject::FAssetRegistryTag& TmpTag : TmpTags)			{				FTagDisplayMetaData& TagMetaData = TagMetaDataMap.FindOrAdd(TmpTag.Name);				TagMetaData.Type = TmpTag.Type;				TagMetaData.DisplayFlags = TmpTag.DisplayFlags;			}		}	}	// Add all asset registry tags and values	for (const auto& TagAndValuePair : AssetData.TagsAndValues)	{		// Skip tags that are not registered#if !ECB_DEBUG		if (bHasTagMetaDataMap && !TagMetaDataMap.Contains(TagAndValuePair.Key))		{			continue;		}#endif		FTagDisplayMetaData* TagMetaData = NULL;		if (bHasTagMetaDataMap && TagMetaDataMap.Contains(TagAndValuePair.Key))		{			TagMetaData = TagMetaDataMap.Find(TagAndValuePair.Key);			// Skip tags that are set to be hidden			if (TagMetaData && TagMetaData->Type == UObject::FAssetRegistryTag::TT_Hidden)			{				continue;			}		}		const bool bHasTagMetaData = TagMetaData != NULL;		FProperty* TagField = AssetClass != NULL ? FindFProperty<FProperty>(AssetClass, TagAndValuePair.Key) : NULL;		// Build the display name for this tag		FText DisplayName;		if (bHasTagMetaData && !TagMetaData->MetaData.DisplayName.IsEmpty())		{			DisplayName = TagMetaData->MetaData.DisplayName;		}		else if (TagField)		{			DisplayName = TagField->GetDisplayNameText();		}		else		{			// We have no type information by this point, so no idea if it's a bool :(			const bool bIsBool = false;			DisplayName = FText::FromString(FName::NameToDisplayString(TagAndValuePair.Key.ToString(), bIsBool));		}		// Build the display value for this tag		FText DisplayValue;		{			auto ReformatNumberStringForDisplay = [](const FString& InNumberString) -> FText			{				// Respect the number of decimal places in the source string when converting for display				int32 NumDecimalPlaces = 0;				{					int32 DotIndex = INDEX_NONE;					if (InNumberString.FindChar(TEXT('.'), DotIndex))					{						NumDecimalPlaces = InNumberString.Len() - DotIndex - 1;					}				}				if (NumDecimalPlaces > 0)				{					// Convert the number as a double					double Num = 0.0;					LexFromString(Num, *InNumberString);					const FNumberFormattingOptions NumFormatOpts = FNumberFormattingOptions()						.SetMinimumFractionalDigits(NumDecimalPlaces)						.SetMaximumFractionalDigits(NumDecimalPlaces);					return FText::AsNumber(Num, &NumFormatOpts);				}				else				{					const bool bIsSigned = InNumberString.Len() > 0 && (InNumberString[0] == TEXT('-') || InNumberString[0] == TEXT('+'));					if (bIsSigned)					{						// Convert the number as a signed int						int64 Num = 0;						LexFromString(Num, *InNumberString);						return FText::AsNumber(Num);					}					else					{						// Convert the number as an unsigned int						uint64 Num = 0;						LexFromString(Num, *InNumberString);						return FText::AsNumber(Num);					}				}				return FText::GetEmpty();			};			bool bHasSetDisplayValue = false;			const FString AttributeValueStr = TagAndValuePair.Value.GetValue();			// Numerical tags need to format the specified number based on the display flags			if (!bHasSetDisplayValue && bHasTagMetaData && TagMetaData->Type == UObject::FAssetRegistryTag::TT_Numerical && AttributeValueStr.IsNumeric())			{				bHasSetDisplayValue = true;				const bool bAsMemory = !!(TagMetaData->DisplayFlags & UObject::FAssetRegistryTag::TD_Memory);				if (bAsMemory)				{					// Memory should be a 64-bit unsigned number of bytes					uint64 NumBytes = 0;					LexFromString(NumBytes, *AttributeValueStr);					DisplayValue = FText::AsMemory(NumBytes);				}				else				{					DisplayValue = ReformatNumberStringForDisplay(AttributeValueStr);				}			}			// Dimensional tags need to be split into their component numbers, with each component number re-format			if (!bHasSetDisplayValue && bHasTagMetaData && TagMetaData->Type == UObject::FAssetRegistryTag::TT_Dimensional)			{				TArray<FString> NumberStrTokens;				AttributeValueStr.ParseIntoArray(NumberStrTokens, TEXT("x"), true);				if (NumberStrTokens.Num() > 0 && NumberStrTokens.Num() <= 3)				{					bHasSetDisplayValue = true;					switch (NumberStrTokens.Num())					{					case 1:						DisplayValue = ReformatNumberStringForDisplay(NumberStrTokens[0]);						break;					case 2:						DisplayValue = FText::Format(LOCTEXT("DisplayTag2xFmt", "{0} \u00D7 {1}"), ReformatNumberStringForDisplay(NumberStrTokens[0]), ReformatNumberStringForDisplay(NumberStrTokens[1]));						break;					case 3:						DisplayValue = FText::Format(LOCTEXT("DisplayTag3xFmt", "{0} \u00D7 {1} \u00D7 {2}"), ReformatNumberStringForDisplay(NumberStrTokens[0]), ReformatNumberStringForDisplay(NumberStrTokens[1]), ReformatNumberStringForDisplay(NumberStrTokens[2]));						break;					default:						break;					}				}			}			// Chronological tags need to format the specified timestamp based on the display flags			if (!bHasSetDisplayValue && bHasTagMetaData && TagMetaData->Type == UObject::FAssetRegistryTag::TT_Chronological)			{				bHasSetDisplayValue = true;				FDateTime Timestamp;				if (FDateTime::Parse(AttributeValueStr, Timestamp))				{					const bool bDisplayDate = !!(TagMetaData->DisplayFlags & UObject::FAssetRegistryTag::TD_Date);					const bool bDisplayTime = !!(TagMetaData->DisplayFlags & UObject::FAssetRegistryTag::TD_Time);					const FString TimeZone = (TagMetaData->DisplayFlags & UObject::FAssetRegistryTag::TD_InvariantTz) ? FText::GetInvariantTimeZone() : FString();					if (bDisplayDate && bDisplayTime)					{						DisplayValue = FText::AsDateTime(Timestamp, EDateTimeStyle::Short, EDateTimeStyle::Short, TimeZone);					}					else if (bDisplayDate)					{						DisplayValue = FText::AsDate(Timestamp, EDateTimeStyle::Short, TimeZone);					}					else if (bDisplayTime)					{						DisplayValue = FText::AsTime(Timestamp, EDateTimeStyle::Short, TimeZone);					}				}			}			// The tag value might be localized text, so we need to parse it for display			if (!bHasSetDisplayValue && FTextStringHelper::IsComplexText(*AttributeValueStr))			{				bHasSetDisplayValue = FTextStringHelper::ReadFromBuffer(*AttributeValueStr, DisplayValue) != nullptr;			}			// Do our best to build something valid from the string value			if (!bHasSetDisplayValue)			{				bHasSetDisplayValue = true;				// Since all we have at this point is a string, we can't be very smart here.				// We need to strip some noise off class paths in some cases, but can't load the asset to inspect its UPROPERTYs manually due to performance concerns.				FString ValueString = FPackageName::ExportTextPathToObjectPath(AttributeValueStr);				const TCHAR StringToRemove[] = TEXT("/Script/");				if (ValueString.StartsWith(StringToRemove))				{					// Remove the class path for native classes, and also remove Engine. for engine classes					const int32 SizeOfPrefix = UE_ARRAY_COUNT(StringToRemove) - 1;					ValueString = ValueString.Mid(SizeOfPrefix, ValueString.Len() - SizeOfPrefix).Replace(TEXT("Engine."), TEXT(""));				}				if (TagField)				{					FProperty* TagProp = nullptr;					UEnum* TagEnum = nullptr;					if (FByteProperty* ByteProp = CastField<FByteProperty>(TagField))					{						TagProp = ByteProp;						TagEnum = ByteProp->Enum;					}					else if (FEnumProperty* EnumProp = CastField<FEnumProperty>(TagField))					{						TagProp = EnumProp;						TagEnum = EnumProp->GetEnum();					}					// Strip off enum prefixes if they exist					if (TagProp)					{						if (TagEnum)						{							const FString EnumPrefix = TagEnum->GenerateEnumPrefix();							if (EnumPrefix.Len() && ValueString.StartsWith(EnumPrefix))							{								ValueString = ValueString.RightChop(EnumPrefix.Len() + 1);	// +1 to skip over the underscore							}						}						ValueString = FName::NameToDisplayString(ValueString, false);					}				}				DisplayValue = FText::FromString(MoveTemp(ValueString));			}									// Add suffix to the value, if one is defined for this tag			if (bHasTagMetaData && !TagMetaData->MetaData.Suffix.IsEmpty())			{				DisplayValue = FText::Format(LOCTEXT("DisplayTagSuffixFmt", "{0} {1}"), DisplayValue, TagMetaData->MetaData.Suffix);			}		}		if (!DisplayValue.IsEmpty())		{			const bool bImportant = bHasTagMetaData && !TagMetaData->MetaData.ImportantValue.IsEmpty() && TagMetaData->MetaData.ImportantValue == TagAndValuePair.Value;			CachedDisplayTags.Add(FTagDisplayItem(TagAndValuePair.Key, DisplayName, DisplayValue, bImportant));		}	}}const FSlateBrush* SExtAssetViewItem::GetBorderImage() const{	return bDraggedOver ? FAppStyle::GetBrush("Menu.Background") : FAppStyle::GetBrush("NoBorder");}bool SExtAssetViewItem::IsFolder() const{	return AssetItem.IsValid() && AssetItem->GetType() == EExtAssetItemType::Folder;}FText SExtAssetViewItem::GetNameText() const{	if(AssetItem.IsValid())	{		if(AssetItem->GetType() != EExtAssetItemType::Folder)		{			auto& AssetData = StaticCastSharedPtr<FExtAssetViewAsset>(AssetItem)->Data;#if ECB_TODO // todo: AssetName should fallback to filename when parsing even invalid			if (AssetData.IsValid() || AssetData.PackageFilePath == NAME_None)			{				return FText::FromName(AssetData.AssetName);			}			else			{				return FText::FromString(FPaths::GetBaseFilename(AssetData.PackageFilePath.ToString()));			}#endif			return FText::FromName(AssetData.AssetName);		}		else		{			return StaticCastSharedPtr<FExtAssetViewFolder>(AssetItem)->FolderName;		}	}	return FText();}FSlateColor SExtAssetViewItem::GetAssetColor() const{	if(AssetItem.IsValid())	{		if(AssetItem->GetType() == EExtAssetItemType::Folder)		{			TSharedPtr<FExtAssetViewFolder> AssetFolderItem = StaticCastSharedPtr<FExtAssetViewFolder>(AssetItem);			TSharedPtr<FLinearColor> Color;#if ECB_WIP_COLLECTION			if (AssetFolderItem->bCollectionFolder)			{				FName CollectionName;				ECollectionShareType::Type CollectionFolderShareType = ECollectionShareType::CST_All;				ContentBrowserUtils::IsCollectionPath(AssetFolderItem->FolderPath, &CollectionName, &CollectionFolderShareType);				Color = CollectionViewUtils::LoadColor( CollectionName.ToString(), CollectionFolderShareType );			}			else#endif			{#if ECB_LEGACY				Color = ExtContentBrowserUtils::LoadColor( AssetFolderItem->FolderPath );#endif			}#if ECB_LEGACY			if ( Color.IsValid() )			{				return *Color.Get();			}			#endif			FLinearColor FolderColor;			if (ExtContentBrowserUtils::LoadFolderColor(AssetFolderItem->FolderPath, FolderColor))			{				return FolderColor;			}			else			{				return ExtContentBrowserUtils::GetDefaultColor();			}		}		else if(AssetTypeActions.IsValid())		{			return AssetTypeActions.Pin()->GetTypeColor().ReinterpretAsLinear();		}	}	return ExtContentBrowserUtils::GetDefaultColor();}void SExtAssetViewItem::SetForceMipLevelsToBeResident(bool bForce) const{#if ECB_LEGACY	if(AssetItem.IsValid() && AssetItem->GetType() == EAssetItemType::Normal)	{		const FExtAssetData& AssetData = StaticCastSharedPtr<FAssetViewAsset>(AssetItem)->Data;		if(AssetData.IsValid() && AssetData.IsAssetLoaded())		{			UObject* Asset = AssetData.GetAsset();			if(Asset != nullptr)			{				if(UTexture2D* Texture2D = Cast<UTexture2D>(Asset))				{					Texture2D->bForceMiplevelsToBeResident = bForce;				}				else if(UMaterial* Material = Cast<UMaterial>(Asset))				{					Material->SetForceMipLevelsToBeResident(bForce, bForce, -1.0f);				}			}		}	}#endif}bool SExtAssetViewItem::OnVisualizeTooltip(const TSharedPtr<SWidget>& TooltipContent){#if ECB_LEGACY	if(OnVisualizeAssetToolTip.IsBound() && TooltipContent.IsValid() && AssetItem->GetType() != EAssetItemType::Folder)	{		FExtAssetData& AssetData = StaticCastSharedPtr<FAssetViewAsset>(AssetItem)->Data;		return OnVisualizeAssetToolTip.Execute(TooltipContent, AssetData);	}#endif	// No custom behaviour, return false to allow slate to visualize the widget	return false;}void SExtAssetViewItem::OnToolTipClosing(){	OnAssetToolTipClosing.ExecuteIfBound();}///////////////////////////////// SExtAssetListItem///////////////////////////////SExtAssetListItem::~SExtAssetListItem(){}BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATIONvoid SExtAssetListItem::Construct( const FArguments& InArgs ){	SExtAssetViewItem::Construct( SExtAssetViewItem::FArguments()		.AssetItem(InArgs._AssetItem)		.OnRenameBegin(InArgs._OnRenameBegin)		.OnRenameCommit(InArgs._OnRenameCommit)		.OnVerifyRenameCommit(InArgs._OnVerifyRenameCommit)		.OnItemDestroyed(InArgs._OnItemDestroyed)		.ShouldAllowToolTip(InArgs._ShouldAllowToolTip)		.ThumbnailEditMode(InArgs._ThumbnailEditMode)		.HighlightText(InArgs._HighlightText)		.OnAssetsOrPathsDragDropped(InArgs._OnAssetsOrPathsDragDropped)		.OnFilesDragDropped(InArgs._OnFilesDragDropped)		.OnIsAssetValidForCustomToolTip(InArgs._OnIsAssetValidForCustomToolTip)		.OnGetCustomAssetToolTip(InArgs._OnGetCustomAssetToolTip)		.OnVisualizeAssetToolTip(InArgs._OnVisualizeAssetToolTip)		.OnAssetToolTipClosing( InArgs._OnAssetToolTipClosing )		);	AssetThumbnail = InArgs._AssetThumbnail;	ItemHeight = InArgs._ItemHeight;	const float ThumbnailPadding = InArgs._ThumbnailPadding;	TSharedPtr<SWidget> Thumbnail;	if ( AssetItem.IsValid() && AssetThumbnail.IsValid() )	{		FExtAssetThumbnailConfig ThumbnailConfig;		ThumbnailConfig.bAllowFadeIn = true;		ThumbnailConfig.bAllowHintText = InArgs._AllowThumbnailHintLabel;		ThumbnailConfig.bForceGenericThumbnail = (AssetItem->GetType() == EExtAssetItemType::Creation);		//ThumbnailConfig.bAllowAssetSpecificThumbnailOverlay = (AssetItem->GetType() != EExtAssetItemType::Creation);		ThumbnailConfig.bAllowAssetSpecificThumbnailOverlay = false;		ThumbnailConfig.ThumbnailLabel = InArgs._ThumbnailLabel;		ThumbnailConfig.HighlightedText = InArgs._HighlightText;		ThumbnailConfig.HintColorAndOpacity = InArgs._ThumbnailHintColorAndOpacity;		Thumbnail = AssetThumbnail->MakeThumbnailWidget(ThumbnailConfig);	}	else	{		Thumbnail = SNew(SImage) .Image( FAppStyle::GetDefaultBrush() );	}	FName ItemShadowBorderName;	TSharedRef<SWidget> ItemContents = FExtAssetViewItemHelper::CreateListItemContents(this, Thumbnail.ToSharedRef(), ItemShadowBorderName);	ChildSlot	[		SNew(SBorder)		.BorderImage(this, &SExtAssetViewItem::GetBorderImage)		.Padding(0)		.AddMetaData<FTagMetaData>(FTagMetaData(AssetItem->GetType() == EExtAssetItemType::Normal ? StaticCastSharedPtr<FExtAssetViewAsset>(AssetItem)->Data.ObjectPath : NAME_None))		[			SNew(SHorizontalBox)			// Viewport			+SHorizontalBox::Slot()			.AutoWidth()			.VAlign(VAlign_Center)			[				SNew( SBox )				.Padding(ThumbnailPadding - 4.f)				.WidthOverride( this, &SExtAssetListItem::GetThumbnailBoxSize )				.HeightOverride( this, &SExtAssetListItem::GetThumbnailBoxSize )				[					// Drop shadow border					SNew(SBorder)					.Padding(4.f)					.BorderImage(FAppStyle::GetBrush(ItemShadowBorderName))					[						ItemContents					]				]			]			+SHorizontalBox::Slot()			.AutoWidth()			.Padding(6, 0, 0, 0)			.VAlign(VAlign_Center)			[				SNew(SVerticalBox)				+SVerticalBox::Slot()				.AutoHeight()				.Padding(0, 1)				[					SAssignNew(InlineRenameWidget, SInlineEditableTextBlock)					.Font(FAppStyle::GetFontStyle("ContentBrowser.AssetTileViewNameFont"))					.Text( GetNameText() )					.OnBeginTextEdit(this, &SExtAssetListItem::HandleBeginNameChange)					.OnTextCommitted(this, &SExtAssetListItem::HandleNameCommitted)					.OnVerifyTextChanged(this, &SExtAssetListItem::HandleVerifyNameChanged)					.HighlightText(InArgs._HighlightText)					.IsSelected(InArgs._IsSelected)					.IsReadOnly(this, &SExtAssetListItem::IsNameReadOnly)				]				+SVerticalBox::Slot()				.AutoHeight()				.Padding(0, 1)				[					// Class					SAssignNew(ClassText, STextBlock)					.Font(FAppStyle::GetFontStyle("ContentBrowser.AssetListViewClassFont"))					.Text(GetAssetClassText())					.HighlightText(InArgs._HighlightText)				]			]		]	];	if(AssetItem.IsValid())	{		AssetItem->RenamedRequestEvent.BindSP(InlineRenameWidget.Get(), &SInlineEditableTextBlock::EnterEditingMode);		AssetItem->RenameCanceledEvent.BindSP(InlineRenameWidget.Get(), &SInlineEditableTextBlock::ExitEditingMode);	}	SetForceMipLevelsToBeResident(true);}END_SLATE_FUNCTION_BUILD_OPTIMIZATIONvoid SExtAssetListItem::OnAssetDataChanged(){	SExtAssetViewItem::OnAssetDataChanged();	if (ClassText.IsValid())	{		ClassText->SetText(GetAssetClassText());	}	if (AssetItem->GetType() != EExtAssetItemType::Folder && AssetThumbnail.IsValid())	{		AssetThumbnail->SetAsset(StaticCastSharedPtr<FExtAssetViewAsset>(AssetItem)->Data);	}}float SExtAssetListItem::GetExtraStateIconWidth() const{	return GetStateIconImageSize().Get();}FOptionalSize SExtAssetListItem::GetExtraStateIconMaxWidth() const{	return GetThumbnailBoxSize().Get() * 0.7;}FOptionalSize SExtAssetListItem::GetStateIconImageSize() const{	float IconSize = GetThumbnailBoxSize().Get() * 0.3;	return IconSize > 12 ? IconSize : 12;}FOptionalSize SExtAssetListItem::GetThumbnailBoxSize() const{	return FOptionalSize( ItemHeight.Get() );}///////////////////////////////// SExtAssetTileItem///////////////////////////////SExtAssetTileItem::~SExtAssetTileItem(){}BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATIONvoid SExtAssetTileItem::Construct( const FArguments& InArgs ){	SExtAssetViewItem::Construct( SExtAssetViewItem::FArguments()		.AssetItem(InArgs._AssetItem)		.OnRenameBegin(InArgs._OnRenameBegin)		.OnRenameCommit(InArgs._OnRenameCommit)		.OnVerifyRenameCommit(InArgs._OnVerifyRenameCommit)		.OnItemDestroyed(InArgs._OnItemDestroyed)		.ShouldAllowToolTip(InArgs._ShouldAllowToolTip)		.ThumbnailEditMode(InArgs._ThumbnailEditMode)		.HighlightText(InArgs._HighlightText)		.OnAssetsOrPathsDragDropped(InArgs._OnAssetsOrPathsDragDropped)		.OnFilesDragDropped(InArgs._OnFilesDragDropped)		.OnIsAssetValidForCustomToolTip(InArgs._OnIsAssetValidForCustomToolTip)		.OnGetCustomAssetToolTip(InArgs._OnGetCustomAssetToolTip)		.OnVisualizeAssetToolTip(InArgs._OnVisualizeAssetToolTip)		.OnAssetToolTipClosing( InArgs._OnAssetToolTipClosing )		);	AssetThumbnail = InArgs._AssetThumbnail;	ItemWidth = InArgs._ItemWidth;	ThumbnailPadding = IsFolder() ? InArgs._ThumbnailPadding + 5.0f : InArgs._ThumbnailPadding;	TSharedPtr<SWidget> Thumbnail;	if ( AssetItem.IsValid() && AssetThumbnail.IsValid() )	{		FExtAssetThumbnailConfig ThumbnailConfig;		ThumbnailConfig.bAllowFadeIn = true;		ThumbnailConfig.bAllowHintText = InArgs._AllowThumbnailHintLabel;		ThumbnailConfig.bForceGenericThumbnail = (AssetItem->GetType() == EExtAssetItemType::Creation);		ThumbnailConfig.bAllowAssetSpecificThumbnailOverlay = true;// (AssetItem->GetType() != EAssetItemType::Creation);		ThumbnailConfig.ThumbnailLabel = InArgs._ThumbnailLabel;		ThumbnailConfig.HighlightedText = InArgs._HighlightText;		ThumbnailConfig.HintColorAndOpacity = InArgs._ThumbnailHintColorAndOpacity;		Thumbnail = AssetThumbnail->MakeThumbnailWidget(ThumbnailConfig);	}	else	{		Thumbnail = SNew(SImage) .Image( FAppStyle::GetDefaultBrush() );	}	FName ItemShadowBorderName;	TSharedRef<SWidget> ItemContents = FExtAssetViewItemHelper::CreateTileItemContents(this, Thumbnail.ToSharedRef(), ItemShadowBorderName);	ChildSlot	[		SNew(SBorder)		.BorderImage(this, &SExtAssetViewItem::GetBorderImage)		.Padding(0)		.AddMetaData<FTagMetaData>(FTagMetaData((AssetItem->GetType() == EExtAssetItemType::Normal) ? StaticCastSharedPtr<FExtAssetViewAsset>(AssetItem)->Data.ObjectPath : ((AssetItem->GetType() == EExtAssetItemType::Folder) ? FName(*StaticCastSharedPtr<FExtAssetViewFolder>(AssetItem)->FolderPath) : NAME_None)))		[			SNew(SVerticalBox)			// Thumbnail			+SVerticalBox::Slot()			.AutoHeight()			.HAlign(HAlign_Center)			[				// The remainder of the space is reserved for the name.				SNew(SBox)				.Padding(ThumbnailPadding - 4.f)				.WidthOverride(this, &SExtAssetTileItem::GetThumbnailBoxSize)				.HeightOverride( this, &SExtAssetTileItem::GetThumbnailBoxSize )				[					// Drop shadow border					SNew(SBorder)					.Padding(4.f)					.BorderImage(FAppStyle::GetBrush(ItemShadowBorderName))					[						ItemContents					]				]			]			+SVerticalBox::Slot()			.Padding(FMargin(1.f, 0))			.HAlign(HAlign_Center)			.VAlign(VAlign_Center)			.FillHeight(1.f)			[				SAssignNew(InlineRenameWidget, SInlineEditableTextBlock)					.Font( this, &SExtAssetTileItem::GetThumbnailFont )					.Text( GetNameText() )					.OnBeginTextEdit(this, &SExtAssetTileItem::HandleBeginNameChange)					.OnTextCommitted(this, &SExtAssetTileItem::HandleNameCommitted)					.OnVerifyTextChanged(this, &SExtAssetTileItem::HandleVerifyNameChanged)					.HighlightText(InArgs._HighlightText)					.IsSelected(InArgs._IsSelected)					.IsReadOnly(this, &SExtAssetTileItem::IsNameReadOnly)					.Justification(ETextJustify::Center)					.LineBreakPolicy(FBreakIterator::CreateCamelCaseBreakIterator())			]		]		];	if(AssetItem.IsValid())	{		AssetItem->RenamedRequestEvent.BindSP(InlineRenameWidget.Get(), &SInlineEditableTextBlock::EnterEditingMode);		AssetItem->RenameCanceledEvent.BindSP(InlineRenameWidget.Get(), &SInlineEditableTextBlock::ExitEditingMode);	}	SetForceMipLevelsToBeResident(true);}END_SLATE_FUNCTION_BUILD_OPTIMIZATIONvoid SExtAssetTileItem::OnAssetDataChanged(){	SExtAssetViewItem::OnAssetDataChanged();	if (AssetItem->GetType() != EExtAssetItemType::Folder && AssetThumbnail.IsValid())	{		AssetThumbnail->SetAsset(StaticCastSharedPtr<FExtAssetViewAsset>(AssetItem)->Data);	}}float SExtAssetTileItem::GetExtraStateIconWidth() const{	return GetStateIconImageSize().Get();}FOptionalSize SExtAssetTileItem::GetExtraStateIconMaxWidth() const{	return GetThumbnailBoxSize().Get() * 0.8;}FOptionalSize SExtAssetTileItem::GetStateIconImageSize() const{	float IconSize = GetThumbnailBoxSize().Get() * 0.2;	return IconSize > 12 ? IconSize : 12;}FOptionalSize SExtAssetTileItem::GetThumbnailBoxSize() const{	return FOptionalSize(ItemWidth.Get());}FSlateFontInfo SExtAssetTileItem::GetThumbnailFont() const{	FOptionalSize ThumbSize = GetThumbnailBoxSize();	if ( ThumbSize.IsSet() )	{		float Size = ThumbSize.Get();		if ( Size < 50 )		{			const static FName SmallFontName("ContentBrowser.AssetTileViewNameFontVerySmall");			return FAppStyle::GetFontStyle(SmallFontName);		}		else if ( Size < 85 )		{			const static FName SmallFontName("ContentBrowser.AssetTileViewNameFontSmall");			return FAppStyle::GetFontStyle(SmallFontName);		}	}	const static FName RegularFont("ContentBrowser.AssetTileViewNameFont");	return FAppStyle::GetFontStyle(RegularFont);}///////////////////////////////// SAssetColumnItem////////////////////////////////** Custom box for the Name column of an asset */class SAssetColumnItemNameBox : public SCompoundWidget{public:	SLATE_BEGIN_ARGS( SAssetColumnItemNameBox ) {}		/** The color of the asset  */		SLATE_ATTRIBUTE( FMargin, Padding )		/** The widget content presented in the box */		SLATE_DEFAULT_SLOT(FArguments, Content)	SLATE_END_ARGS()	~SAssetColumnItemNameBox() {}	void Construct( const FArguments& InArgs, const TSharedRef<SExtAssetColumnItem>& InOwnerAssetColumnItem )	{		OwnerAssetColumnItem = InOwnerAssetColumnItem;		ChildSlot		[			SNew(SBox)			.Padding(InArgs._Padding)			[				InArgs._Content.Widget			]		];	}	virtual TSharedPtr<IToolTip> GetToolTip() override	{		if ( OwnerAssetColumnItem.IsValid() )		{			return OwnerAssetColumnItem.Pin()->GetToolTip();		}		return nullptr;	}	/** Forward the event to the view item that this name box belongs to */	virtual void OnToolTipClosing() override	{		if ( OwnerAssetColumnItem.IsValid() )		{			OwnerAssetColumnItem.Pin()->OnToolTipClosing();		}	}private:	TWeakPtr<SExtAssetViewItem> OwnerAssetColumnItem;};void SExtAssetColumnItem::Construct( const FArguments& InArgs ){	SExtAssetViewItem::Construct( SExtAssetViewItem::FArguments()		.AssetItem(InArgs._AssetItem)		.OnRenameBegin(InArgs._OnRenameBegin)		.OnRenameCommit(InArgs._OnRenameCommit)		.OnVerifyRenameCommit(InArgs._OnVerifyRenameCommit)		.OnItemDestroyed(InArgs._OnItemDestroyed)		.HighlightText(InArgs._HighlightText)		.OnAssetsOrPathsDragDropped(InArgs._OnAssetsOrPathsDragDropped)		.OnFilesDragDropped(InArgs._OnFilesDragDropped)		.OnIsAssetValidForCustomToolTip(InArgs._OnIsAssetValidForCustomToolTip)		.OnGetCustomAssetToolTip(InArgs._OnGetCustomAssetToolTip)		.OnVisualizeAssetToolTip(InArgs._OnVisualizeAssetToolTip)		.OnAssetToolTipClosing(InArgs._OnAssetToolTipClosing)		);		HighlightText = InArgs._HighlightText;}BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATIONTSharedRef<SWidget> SExtAssetColumnItem::GenerateWidgetForColumn( const FName& ColumnName, FIsSelected InIsSelected ){	TSharedPtr<SWidget> Content;	// A little right padding so text from this column does not run directly into text from the next.	static const FMargin ColumnItemPadding( 5, 0, 5, 0 );	if ( ColumnName == "Name" )	{		const FSlateBrush* IconBrush;		if(IsFolder())		{			IconBrush = FAppStyle::GetBrush("ContentBrowser.ColumnViewFolderIcon");		}		else		{			IconBrush = FAppStyle::GetBrush("ContentBrowser.ColumnViewAssetIcon");		}		// Make icon overlays (eg, SCC and dirty status) a reasonable size in relation to the icon size (note: it is assumed this icon is square)		const float IconOverlaySize = IconBrush->ImageSize.X * 0.6f;		Content = SNew(SHorizontalBox)			.AddMetaData<FTagMetaData>(FTagMetaData(AssetItem->GetType() == EExtAssetItemType::Normal ? StaticCastSharedPtr<FExtAssetViewAsset>(AssetItem)->Data.ObjectPath : NAME_None))			// Icon			+SHorizontalBox::Slot()			.AutoWidth()			.Padding(0, 0, 4, 0)			[				SNew(SOverlay)								// The actual icon				+SOverlay::Slot()				[					SNew(SImage)					.Image( IconBrush )					.ColorAndOpacity(this, &SExtAssetColumnItem::GetAssetColor)				]				// Source control state				+SOverlay::Slot()				.HAlign(HAlign_Right)				.VAlign(VAlign_Top)				[					SNew(SBox)					.WidthOverride(IconOverlaySize)					.HeightOverride(IconOverlaySize)					[						SAssignNew(SCCStateWidget, SLayeredImage)						.Image(FStyleDefaults::GetNoBrush())					]				]				// Extra external state hook				+ SOverlay::Slot()				.HAlign(HAlign_Left)				.VAlign(VAlign_Top)				[					SNew(SBox)					.HeightOverride(IconOverlaySize)					.MaxDesiredWidth(IconOverlaySize)					[						GenerateExtraStateIconWidget(IconOverlaySize)					]				]				// Dirty state				+SOverlay::Slot()				.HAlign(HAlign_Left)				.VAlign(VAlign_Bottom)				[					SNew(SBox)					.WidthOverride(IconOverlaySize)					.HeightOverride(IconOverlaySize)					[						SNew(SImage)						.Image(this, &SExtAssetColumnItem::GetDirtyImage)					]				]			]			// Editable Name			+SHorizontalBox::Slot()			.AutoWidth()			[				SAssignNew(InlineRenameWidget, SInlineEditableTextBlock)				.Text( GetNameText() )				.OnBeginTextEdit(this, &SExtAssetColumnItem::HandleBeginNameChange)				.OnTextCommitted(this, &SExtAssetColumnItem::HandleNameCommitted)				.OnVerifyTextChanged(this, &SExtAssetColumnItem::HandleVerifyNameChanged)				.HighlightText(HighlightText)				.IsSelected(InIsSelected)				.IsReadOnly(this, &SExtAssetColumnItem::IsNameReadOnly)			];		if(AssetItem.IsValid())		{			AssetItem->RenamedRequestEvent.BindSP(InlineRenameWidget.Get(), &SInlineEditableTextBlock::EnterEditingMode);			AssetItem->RenameCanceledEvent.BindSP(InlineRenameWidget.Get(), &SInlineEditableTextBlock::ExitEditingMode);		}		return SNew(SBorder)			.BorderImage(this, &SExtAssetViewItem::GetBorderImage)			.Padding(0)			.VAlign(VAlign_Center)			.HAlign(HAlign_Left)			[				SNew( SAssetColumnItemNameBox, SharedThis(this) )				.Padding( ColumnItemPadding )				[					Content.ToSharedRef()				]			];	}	else if ( ColumnName == "Class" )	{		Content = SAssignNew(ClassText, STextBlock)			.ToolTipText( this, &SExtAssetColumnItem::GetAssetClassText )			.Text( GetAssetClassText() )			.HighlightText( HighlightText );	}	else if ( ColumnName == "Path" )	{		Content = SAssignNew(PathText, STextBlock)			.ToolTipText( this, &SExtAssetColumnItem::GetAssetPathText )			.Text( GetAssetPathText() )			.HighlightText( HighlightText );	}	else	{		Content = SNew(STextBlock)			.ToolTipText( TAttribute<FText>::Create( TAttribute<FText>::FGetter::CreateSP(this, &SExtAssetColumnItem::GetAssetTagText, ColumnName) ) )			.Text( TAttribute<FText>::Create( TAttribute<FText>::FGetter::CreateSP(this, &SExtAssetColumnItem::GetAssetTagText, ColumnName) ) );	}	return SNew(SBox)		.Padding( ColumnItemPadding )		.VAlign(VAlign_Center)		.HAlign(HAlign_Left)		[			Content.ToSharedRef()		];}END_SLATE_FUNCTION_BUILD_OPTIMIZATIONvoid SExtAssetColumnItem::OnAssetDataChanged(){	SExtAssetViewItem::OnAssetDataChanged();	if ( ClassText.IsValid() )	{		ClassText->SetText( GetAssetClassText() );	}	if ( PathText.IsValid() )	{		PathText->SetText( GetAssetPathText() );	}}FString SExtAssetColumnItem::GetAssetNameToolTipText() const{	if ( AssetItem.IsValid() )	{		if(AssetItem->GetType() == EExtAssetItemType::Folder)		{			FString Result = StaticCastSharedPtr<FExtAssetViewFolder>(AssetItem)->FolderName.ToString();			Result += TEXT("\n");			Result += LOCTEXT("FolderName", "Folder").ToString();			return Result;		}		else		{			const FString AssetName = StaticCastSharedPtr<FExtAssetViewAsset>(AssetItem)->Data.AssetName.ToString();			const FString AssetType = StaticCastSharedPtr<FExtAssetViewAsset>(AssetItem)->Data.AssetClass.ToString();			FString Result = AssetName;			Result += TEXT("\n");			Result += AssetType;			return Result;		}	}	else	{		return FString();	}}FText SExtAssetColumnItem::GetAssetPathText() const{	if ( AssetItem.IsValid() )	{		if(AssetItem->GetType() != EExtAssetItemType::Folder)		{			return FText::FromName(StaticCastSharedPtr<FExtAssetViewAsset>(AssetItem)->Data.PackageFilePath);		}		else		{			return FText::FromString(StaticCastSharedPtr<FExtAssetViewFolder>(AssetItem)->FolderPath);		}	}	else	{		return FText();	}}FText SExtAssetColumnItem::GetAssetTagText(FName AssetTag) const{	if ( AssetItem.IsValid() )	{		if(AssetItem->GetType() != EExtAssetItemType::Folder)		{			const TSharedPtr<FExtAssetViewAsset>& ItemAsAsset = StaticCastSharedPtr<FExtAssetViewAsset>(AssetItem);			// Check custom type			{				FText* FoundText = ItemAsAsset->CustomColumnDisplayText.Find(AssetTag);				if (FoundText)				{					return *FoundText;				}			}			// Check display tags			{				const FTagDisplayItem* FoundTagItem = CachedDisplayTags.FindByPredicate([AssetTag](const FTagDisplayItem& TagItem)				{					return TagItem.TagKey == AssetTag;				});				if (FoundTagItem)				{					return FoundTagItem->DisplayValue;				}			}		}	}		return FText();}#undef LOCTEXT_NAMESPACE
 |