2020-10-28 06:51:40 -04:00
// Copyright Epic Games, Inc. All Rights Reserved.
# include "DataLayerMode.h"
2022-08-30 23:03:03 -04:00
# include "ActorDescTreeItem.h"
# include "ActorMode.h"
# include "Algo/AnyOf.h"
2023-04-11 11:30:47 -04:00
# include "Algo/AllOf.h"
2022-08-30 23:03:03 -04:00
# include "Algo/Transform.h"
2022-10-26 17:33:05 -04:00
# include "Algo/Accumulate.h"
# include "AssetRegistry/IAssetRegistry.h"
# include "AssetRegistry/AssetRegistryModule.h"
# include "AssetSelection.h"
2022-08-30 23:03:03 -04:00
# include "AssetRegistry/AssetData.h"
# include "Containers/EnumAsByte.h"
# include "Containers/IndirectArray.h"
# include "Containers/SparseArray.h"
2023-10-06 14:34:17 -04:00
# include "ContentBrowserDelegates.h"
2022-03-31 17:43:23 -04:00
# include "ContentBrowserModule.h"
2022-08-30 23:03:03 -04:00
# include "DataLayer/DataLayerDragDropOp.h"
2020-10-28 06:51:40 -04:00
# include "DataLayer/DataLayerEditorSubsystem.h"
2021-11-07 23:43:01 -05:00
# include "DataLayer/DataLayerOutlinerDeleteButtonColumn.h"
# include "DataLayer/SDataLayerOutliner.h"
2020-10-28 06:51:40 -04:00
# include "DataLayerActorTreeItem.h"
2022-08-30 23:03:03 -04:00
# include "DataLayerHierarchy.h"
2020-10-28 06:51:40 -04:00
# include "DataLayerTreeItem.h"
2023-02-02 18:41:35 -05:00
# include "DataLayerEditorModule.h"
2022-08-30 23:03:03 -04:00
# include "DataLayersActorDescTreeItem.h"
# include "DragAndDrop/ActorDragDropOp.h"
# include "DragAndDrop/CompositeDragDropOp.h"
# include "DragAndDrop/FolderDragDropOp.h"
# include "Editor.h"
# include "Editor/EditorEngine.h"
# include "EditorActorFolders.h"
# include "Engine/Engine.h"
# include "Engine/EngineBaseTypes.h"
# include "Engine/EngineTypes.h"
# include "Engine/Level.h"
# include "Engine/World.h"
# include "Framework/Application/SlateApplication.h"
# include "Framework/Commands/UIAction.h"
# include "Framework/Commands/UICommandInfo.h"
2022-11-21 17:19:31 -05:00
# include "Framework/Commands/UICommandList.h"
2022-08-30 23:03:03 -04:00
# include "Framework/MultiBox/MultiBoxBuilder.h"
# include "GameFramework/Actor.h"
# include "GenericPlatform/ICursor.h"
# include "HAL/PlatformCrt.h"
# include "HAL/PlatformMath.h"
# include "IContentBrowserSingleton.h"
# include "ISceneOutlinerHierarchy.h"
# include "Input/DragAndDrop.h"
# include "Input/Events.h"
# include "InputCoreTypes.h"
# include "Internationalization/Internationalization.h"
2022-05-10 10:22:54 -04:00
# include "LevelInstance/LevelInstanceEditorInstanceActor.h"
# include "LevelInstance/LevelInstanceInterface.h"
2022-08-30 23:03:03 -04:00
# include "LevelInstance/LevelInstanceSubsystem.h"
# include "Misc/AssertionMacros.h"
# include "Modules/ModuleManager.h"
2023-10-06 14:34:17 -04:00
# include "PropertyCustomizationHelpers.h"
2022-08-30 23:03:03 -04:00
# include "SDataLayerBrowser.h"
# include "SSceneOutliner.h"
# include "SceneOutlinerFilters.h"
2020-10-28 06:51:40 -04:00
# include "SceneOutlinerMenuContext.h"
2022-08-30 23:03:03 -04:00
# include "SceneOutlinerPublicTypes.h"
2022-05-16 08:48:27 -04:00
# include "ScopedTransaction.h"
2020-10-28 07:24:36 -04:00
# include "Selection.h"
2022-08-30 23:03:03 -04:00
# include "SlotBase.h"
# include "Templates/Casts.h"
# include "Templates/Tuple.h"
# include "Templates/TypeHash.h"
# include "Templates/UnrealTemplate.h"
# include "Textures/SlateIcon.h"
2022-11-21 17:19:31 -05:00
# include "Toolkits/GlobalEditorCommonCommands.h"
2022-08-30 23:03:03 -04:00
# include "ToolMenu.h"
# include "ToolMenuContext.h"
# include "ToolMenuDelegates.h"
# include "ToolMenuEntry.h"
# include "ToolMenuSection.h"
# include "ToolMenus.h"
2024-01-30 14:18:27 -05:00
# include "Settings/EditorExperimentalSettings.h"
2022-08-30 23:03:03 -04:00
# include "UObject/Class.h"
# include "UObject/NameTypes.h"
# include "UObject/ObjectPtr.h"
# include "UObject/TopLevelAssetPath.h"
# include "UObject/UObjectGlobals.h"
# include "UObject/UnrealNames.h"
# include "Widgets/DeclarativeSyntaxSupport.h"
# include "Widgets/SBoxPanel.h"
# include "Widgets/Views/STreeView.h"
2024-01-30 14:18:27 -05:00
# include "FolderTreeItem.h"
2022-08-30 23:03:03 -04:00
# include "WorldDataLayersTreeItem.h"
# include "WorldPartition/DataLayer/DataLayerAsset.h"
# include "WorldPartition/DataLayer/DataLayerInstance.h"
# include "WorldPartition/DataLayer/DataLayerInstanceWithAsset.h"
2023-01-31 17:03:25 -05:00
# include "WorldPartition/DataLayer/DataLayerManager.h"
2024-02-21 14:52:19 -05:00
# include "WorldPartition/DataLayer/DataLayerUtils.h"
2024-01-30 14:18:27 -05:00
# include "WorldPartition/DataLayer/ExternalDataLayerAsset.h"
# include "WorldPartition/DataLayer/ExternalDataLayerInstance.h"
# include "WorldPartition/DataLayer/ExternalDataLayerManager.h"
2022-08-30 23:03:03 -04:00
# include "WorldPartition/DataLayer/WorldDataLayers.h"
2024-01-30 14:18:27 -05:00
# include "WorldPartition/WorldPartition.h"
2022-08-30 23:03:03 -04:00
# include "WorldPartition/WorldPartitionEditorPerProjectUserSettings.h"
# include "WorldTreeItem.h"
class FWorldPartitionActorDesc ;
class SWidget ;
class UObject ;
2020-10-28 06:51:40 -04:00
# define LOCTEXT_NAMESPACE "DataLayer"
2021-11-07 23:43:01 -05:00
using FDataLayerFilter = TSceneOutlinerPredicateFilter < FDataLayerTreeItem > ;
using FDataLayerActorFilter = TSceneOutlinerPredicateFilter < FDataLayerActorTreeItem > ;
using FActorDescFilter = TSceneOutlinerPredicateFilter < FActorDescTreeItem > ;
FDataLayerModeParams : : FDataLayerModeParams ( SSceneOutliner * InSceneOutliner , SDataLayerBrowser * InDataLayerBrowser , const TWeakObjectPtr < UWorld > & InSpecifiedWorldToDisplay , FOnSceneOutlinerItemPicked InOnItemPicked )
2020-10-28 06:51:40 -04:00
: SpecifiedWorldToDisplay ( InSpecifiedWorldToDisplay )
, DataLayerBrowser ( InDataLayerBrowser )
, SceneOutliner ( InSceneOutliner )
2021-11-07 23:43:01 -05:00
, OnItemPicked ( InOnItemPicked )
2020-10-28 06:51:40 -04:00
{ }
FDataLayerMode : : FDataLayerMode ( const FDataLayerModeParams & Params )
: ISceneOutlinerMode ( Params . SceneOutliner )
2021-11-07 23:43:01 -05:00
, OnItemPicked ( Params . OnItemPicked )
2020-10-28 06:51:40 -04:00
, DataLayerBrowser ( Params . DataLayerBrowser )
, SpecifiedWorldToDisplay ( Params . SpecifiedWorldToDisplay )
2021-11-07 23:43:01 -05:00
, FilteredDataLayerCount ( 0 )
2020-10-28 06:51:40 -04:00
{
2022-11-21 17:19:31 -05:00
Commands = MakeShareable ( new FUICommandList ( ) ) ;
Commands - > MapAction ( FGlobalEditorCommonCommands : : Get ( ) . FindInContentBrowser , FUIAction (
FExecuteAction : : CreateRaw ( this , & FDataLayerMode : : FindInContentBrowser ) ,
FCanExecuteAction : : CreateRaw ( this , & FDataLayerMode : : CanFindInContentBrowser )
) ) ;
2021-11-25 13:51:47 -05:00
USelection : : SelectionChangedEvent . AddRaw ( this , & FDataLayerMode : : OnLevelSelectionChanged ) ;
USelection : : SelectObjectEvent . AddRaw ( this , & FDataLayerMode : : OnLevelSelectionChanged ) ;
2024-04-15 09:16:36 -04:00
FCoreUObjectDelegates : : PostLoadMapWithWorld . AddRaw ( this , & FDataLayerMode : : OnPostLoadMapWithWorld ) ;
2021-11-25 13:51:47 -05:00
2021-11-07 23:43:01 -05:00
UWorldPartitionEditorPerProjectUserSettings * SharedSettings = GetMutableDefault < UWorldPartitionEditorPerProjectUserSettings > ( ) ;
bHideEditorDataLayers = SharedSettings - > bHideEditorDataLayers ;
bHideRuntimeDataLayers = SharedSettings - > bHideRuntimeDataLayers ;
bHideDataLayerActors = SharedSettings - > bHideDataLayerActors ;
bHideUnloadedActors = SharedSettings - > bHideUnloadedActors ;
2021-11-25 13:51:47 -05:00
bShowOnlySelectedActors = SharedSettings - > bShowOnlySelectedActors ;
bHighlightSelectedDataLayers = SharedSettings - > bHighlightSelectedDataLayers ;
2022-05-10 10:22:54 -04:00
bHideLevelInstanceContent = SharedSettings - > bHideLevelInstanceContent ;
2021-11-25 13:51:47 -05:00
FSceneOutlinerFilterInfo ShowOnlySelectedActorsInfo ( LOCTEXT ( " ToggleShowOnlySelected " , " Only Selected " ) , LOCTEXT ( " ToggleShowOnlySelectedToolTip " , " When enabled, only displays actors that are currently selected. " ) , bShowOnlySelectedActors , FCreateSceneOutlinerFilter : : CreateStatic ( & FDataLayerMode : : CreateShowOnlySelectedActorsFilter ) ) ;
ShowOnlySelectedActorsInfo . OnToggle ( ) . AddLambda ( [ this ] ( bool bIsActive )
{
UWorldPartitionEditorPerProjectUserSettings * Settings = GetMutableDefault < UWorldPartitionEditorPerProjectUserSettings > ( ) ;
Settings - > bShowOnlySelectedActors = bShowOnlySelectedActors = bIsActive ;
Settings - > PostEditChange ( ) ;
if ( auto DataLayerHierarchy = StaticCast < FDataLayerHierarchy * > ( Hierarchy . Get ( ) ) )
{
DataLayerHierarchy - > SetShowOnlySelectedActors ( bIsActive ) ;
}
RefreshSelection ( ) ;
} ) ;
FilterInfoMap . Add ( TEXT ( " ShowOnlySelectedActors " ) , ShowOnlySelectedActorsInfo ) ;
2021-11-07 23:43:01 -05:00
FSceneOutlinerFilterInfo HideEditorDataLayersInfo ( LOCTEXT ( " ToggleHideEditorDataLayers " , " Hide Editor Data Layers " ) , LOCTEXT ( " ToggleHideEditorDataLayersToolTip " , " When enabled, hides Editor Data Layers. " ) , bHideEditorDataLayers , FCreateSceneOutlinerFilter : : CreateStatic ( & FDataLayerMode : : CreateHideEditorDataLayersFilter ) ) ;
HideEditorDataLayersInfo . OnToggle ( ) . AddLambda ( [ this ] ( bool bIsActive )
{
UWorldPartitionEditorPerProjectUserSettings * Settings = GetMutableDefault < UWorldPartitionEditorPerProjectUserSettings > ( ) ;
Settings - > bHideEditorDataLayers = bHideEditorDataLayers = bIsActive ;
Settings - > PostEditChange ( ) ;
if ( auto DataLayerHierarchy = StaticCast < FDataLayerHierarchy * > ( Hierarchy . Get ( ) ) )
{
2021-11-25 13:51:47 -05:00
DataLayerHierarchy - > SetShowEditorDataLayers ( ! bIsActive ) ;
2021-11-07 23:43:01 -05:00
}
} ) ;
FilterInfoMap . Add ( TEXT ( " HideEditorDataLayersFilter " ) , HideEditorDataLayersInfo ) ;
FSceneOutlinerFilterInfo HideRuntimeDataLayersInfo ( LOCTEXT ( " ToggleHideRuntimeDataLayers " , " Hide Runtime Data Layers " ) , LOCTEXT ( " ToggleHideRuntimeDataLayersToolTip " , " When enabled, hides Runtime Data Layers. " ) , bHideRuntimeDataLayers , FCreateSceneOutlinerFilter : : CreateStatic ( & FDataLayerMode : : CreateHideRuntimeDataLayersFilter ) ) ;
HideRuntimeDataLayersInfo . OnToggle ( ) . AddLambda ( [ this ] ( bool bIsActive )
{
UWorldPartitionEditorPerProjectUserSettings * Settings = GetMutableDefault < UWorldPartitionEditorPerProjectUserSettings > ( ) ;
Settings - > bHideRuntimeDataLayers = bHideRuntimeDataLayers = bIsActive ;
Settings - > PostEditChange ( ) ;
if ( auto DataLayerHierarchy = StaticCast < FDataLayerHierarchy * > ( Hierarchy . Get ( ) ) )
{
2021-11-25 13:51:47 -05:00
DataLayerHierarchy - > SetShowRuntimeDataLayers ( ! bIsActive ) ;
2021-11-07 23:43:01 -05:00
}
} ) ;
FilterInfoMap . Add ( TEXT ( " HideRuntimeDataLayersFilter " ) , HideRuntimeDataLayersInfo ) ;
FSceneOutlinerFilterInfo HideDataLayerActorsInfo ( LOCTEXT ( " ToggleHideDataLayerActors " , " Hide Actors " ) , LOCTEXT ( " ToggleHideDataLayerActorsToolTip " , " When enabled, hides Data Layer Actors. " ) , bHideDataLayerActors , FCreateSceneOutlinerFilter : : CreateStatic ( & FDataLayerMode : : CreateHideDataLayerActorsFilter ) ) ;
HideDataLayerActorsInfo . OnToggle ( ) . AddLambda ( [ this ] ( bool bIsActive )
{
UWorldPartitionEditorPerProjectUserSettings * Settings = GetMutableDefault < UWorldPartitionEditorPerProjectUserSettings > ( ) ;
Settings - > bHideDataLayerActors = bHideDataLayerActors = bIsActive ;
Settings - > PostEditChange ( ) ;
if ( auto DataLayerHierarchy = StaticCast < FDataLayerHierarchy * > ( Hierarchy . Get ( ) ) )
{
2021-11-25 13:51:47 -05:00
DataLayerHierarchy - > SetShowDataLayerActors ( ! bIsActive ) ;
2021-11-07 23:43:01 -05:00
}
} ) ;
FilterInfoMap . Add ( TEXT ( " HideDataLayerActorsFilter " ) , HideDataLayerActorsInfo ) ;
FSceneOutlinerFilterInfo HideUnloadedActorsInfo ( LOCTEXT ( " ToggleHideUnloadedActors " , " Hide Unloaded Actors " ) , LOCTEXT ( " ToggleHideUnloadedActorsToolTip " , " When enabled, hides all unloaded world partition actors. " ) , bHideUnloadedActors , FCreateSceneOutlinerFilter : : CreateStatic ( & FDataLayerMode : : CreateHideUnloadedActorsFilter ) ) ;
HideUnloadedActorsInfo . OnToggle ( ) . AddLambda ( [ this ] ( bool bIsActive )
{
UWorldPartitionEditorPerProjectUserSettings * Settings = GetMutableDefault < UWorldPartitionEditorPerProjectUserSettings > ( ) ;
Settings - > bHideUnloadedActors = bHideUnloadedActors = bIsActive ;
Settings - > PostEditChange ( ) ;
if ( auto DataLayerHierarchy = StaticCast < FDataLayerHierarchy * > ( Hierarchy . Get ( ) ) )
{
2021-11-25 13:51:47 -05:00
DataLayerHierarchy - > SetShowUnloadedActors ( ! bIsActive ) ;
2021-11-07 23:43:01 -05:00
}
} ) ;
FilterInfoMap . Add ( TEXT ( " HideUnloadedActorsFilter " ) , HideUnloadedActorsInfo ) ;
2023-09-01 13:03:00 -04:00
// Add a an actor filter and interactive filter which sets the interactive mode of LevelInstance items and their children
SceneOutliner - > AddFilter ( MakeShared < FDataLayerActorFilter > (
FDataLayerActorTreeItem : : FFilterPredicate : : CreateLambda ( [ this ] ( const AActor * Actor , const UDataLayerInstance * DataLayer )
2022-05-10 10:22:54 -04:00
{
2023-09-01 13:03:00 -04:00
return FActorMode : : IsActorDisplayable ( SceneOutliner , Actor , ! bHideLevelInstanceContent ) ;
} ) ,
FSceneOutlinerFilter : : EDefaultBehaviour : : Pass ,
FDataLayerActorTreeItem : : FInteractivePredicate : : CreateLambda ( [ this ] ( const AActor * Actor , const UDataLayerInstance * DataLayer )
2022-05-10 10:22:54 -04:00
{
2023-09-01 13:03:00 -04:00
if ( ! bHideLevelInstanceContent )
2022-05-10 10:22:54 -04:00
{
2023-09-01 13:03:00 -04:00
if ( const ULevelInstanceSubsystem * LevelInstanceSubsystem = UWorld : : GetSubsystem < ULevelInstanceSubsystem > ( RepresentingWorld . Get ( ) ) )
2022-05-10 10:22:54 -04:00
{
2023-09-01 13:03:00 -04:00
const ILevelInstanceInterface * ParentLevelInstance = LevelInstanceSubsystem - > GetParentLevelInstance ( Actor ) ;
if ( ParentLevelInstance & & ! LevelInstanceSubsystem - > IsEditingLevelInstance ( ParentLevelInstance ) )
{
return false ;
}
2022-05-10 10:22:54 -04:00
}
}
2023-09-01 13:03:00 -04:00
return true ;
} ) ) ) ;
2022-05-10 10:22:54 -04:00
2020-10-28 06:51:40 -04:00
DataLayerEditorSubsystem = UDataLayerEditorSubsystem : : Get ( ) ;
Rebuild ( ) ;
const_cast < FSharedSceneOutlinerData & > ( SceneOutliner - > GetSharedData ( ) ) . CustomDelete = FCustomSceneOutlinerDeleteDelegate : : CreateRaw ( this , & FDataLayerMode : : DeleteItems ) ;
}
2021-11-25 13:51:47 -05:00
FDataLayerMode : : ~ FDataLayerMode ( )
{
USelection : : SelectionChangedEvent . RemoveAll ( this ) ;
USelection : : SelectObjectEvent . RemoveAll ( this ) ;
2024-04-15 09:16:36 -04:00
FCoreUObjectDelegates : : PostLoadMapWithWorld . RemoveAll ( this ) ;
2021-11-25 13:51:47 -05:00
}
2021-11-07 23:43:01 -05:00
TSharedRef < FSceneOutlinerFilter > FDataLayerMode : : CreateHideEditorDataLayersFilter ( )
{
2022-03-15 13:52:28 -04:00
return MakeShareable ( new FDataLayerFilter ( FDataLayerTreeItem : : FFilterPredicate : : CreateStatic ( [ ] ( const UDataLayerInstance * DataLayerInstance ) { return true ; } ) , FSceneOutlinerFilter : : EDefaultBehaviour : : Pass ) ) ;
2021-11-07 23:43:01 -05:00
}
TSharedRef < FSceneOutlinerFilter > FDataLayerMode : : CreateHideRuntimeDataLayersFilter ( )
{
2022-03-15 13:52:28 -04:00
return MakeShareable ( new FDataLayerFilter ( FDataLayerTreeItem : : FFilterPredicate : : CreateStatic ( [ ] ( const UDataLayerInstance * DataLayerInstance ) { return true ; } ) , FSceneOutlinerFilter : : EDefaultBehaviour : : Pass ) ) ;
2021-11-07 23:43:01 -05:00
}
TSharedRef < FSceneOutlinerFilter > FDataLayerMode : : CreateHideDataLayerActorsFilter ( )
{
2022-05-10 10:22:54 -04:00
return MakeShareable ( new FDataLayerActorFilter ( FDataLayerActorTreeItem : : FFilterPredicate : : CreateStatic ( [ ] ( const AActor * Actor , const UDataLayerInstance * DataLayerInstance ) { return true ; } ) , FSceneOutlinerFilter : : EDefaultBehaviour : : Pass ) ) ;
2021-11-07 23:43:01 -05:00
}
TSharedRef < FSceneOutlinerFilter > FDataLayerMode : : CreateHideUnloadedActorsFilter ( )
{
WorldPartition: Add UActorDescContainerInstance/FWorldPartitionActorDescInstance which take transient/context data from UActorDescContainer/FWorldPartitionActorDesc leaving them as pure on disk representations.
- UActorDescContainerInstance contains: Transform, ContainerID, InstancingContext
- FWorldPartitionActorDescInstance contains: ResolvedDataLayers, RefCounts, Remapped Instanced actor path, Actor loading code
#rb JeanFrancois.Dube, Richard.Malo, Sebastien.Lussier
#tests editor, cook, pie, hlod builder, level instance, internal projects
[CL 30260359 by patrick enfedaque in ue5-main branch]
2023-12-12 06:59:42 -05:00
return MakeShareable ( new FActorDescFilter ( FActorDescTreeItem : : FFilterPredicate : : CreateStatic ( [ ] ( const FWorldPartitionActorDescInstance * ActorDescInstance ) { return true ; } ) , FSceneOutlinerFilter : : EDefaultBehaviour : : Pass ) ) ;
2021-11-07 23:43:01 -05:00
}
2020-10-28 06:51:40 -04:00
int32 FDataLayerMode : : GetTypeSortPriority ( const ISceneOutlinerTreeItem & Item ) const
{
2022-05-10 10:22:54 -04:00
if ( Item . IsA < FWorldDataLayersTreeItem > ( ) )
{
FWorldDataLayersTreeItem * WorldDataLayersTreeItem = ( FWorldDataLayersTreeItem * ) & Item ;
return static_cast < int32 > ( EItemSortOrder : : WorldDataLayers ) + WorldDataLayersTreeItem - > GetSortPriority ( ) ;
}
else if ( Item . IsA < FDataLayerTreeItem > ( ) )
2020-10-28 06:51:40 -04:00
{
2021-05-04 17:24:35 -04:00
return static_cast < int32 > ( EItemSortOrder : : DataLayer ) ;
2020-10-28 06:51:40 -04:00
}
2023-03-24 08:26:31 -04:00
else if ( Item . IsA < FDataLayerActorTreeItem > ( ) | | Item . IsA < FDataLayerActorDescTreeItem > ( ) )
2020-10-28 06:51:40 -04:00
{
2021-05-04 17:24:35 -04:00
return static_cast < int32 > ( EItemSortOrder : : Actor ) ;
}
2020-10-28 06:51:40 -04:00
// Warning: using actor mode with an unsupported item type!
check ( false ) ;
return - 1 ;
}
2021-02-09 15:01:37 -04:00
bool FDataLayerMode : : CanRenameItem ( const ISceneOutlinerTreeItem & Item ) const
{
if ( Item . IsValid ( ) & & ( Item . IsA < FDataLayerTreeItem > ( ) ) )
{
FDataLayerTreeItem * DataLayerTreeItem = ( FDataLayerTreeItem * ) & Item ;
2024-01-30 14:18:27 -05:00
return ! DataLayerTreeItem - > GetDataLayer ( ) - > IsReadOnly ( ) & & DataLayerTreeItem - > GetDataLayer ( ) - > CanEditDataLayerShortName ( ) ;
2021-02-09 15:01:37 -04:00
}
return false ;
}
2021-01-27 13:03:11 -04:00
FText FDataLayerMode : : GetStatusText ( ) const
{
2021-11-07 23:43:01 -05:00
// The number of DataLayers in the outliner before applying the text filter
const int32 TotalDataLayerCount = ApplicableDataLayers . Num ( ) ;
const int32 SelectedDataLayerCount = SceneOutliner - > GetSelection ( ) . Num < FDataLayerTreeItem > ( ) ;
if ( ! SceneOutliner - > IsTextFilterActive ( ) )
2021-01-27 13:03:11 -04:00
{
2021-11-07 23:43:01 -05:00
if ( SelectedDataLayerCount = = 0 )
2021-01-27 13:03:11 -04:00
{
2021-11-25 13:51:47 -05:00
return FText : : Format ( LOCTEXT ( " ShowingAllDataLayersFmt " , " {0} data layers " ) , FText : : AsNumber ( FilteredDataLayerCount ) ) ;
2021-11-07 23:43:01 -05:00
}
else
{
return FText : : Format ( LOCTEXT ( " ShowingAllDataLayersSelectedFmt " , " {0} data layers ({1} selected) " ) , FText : : AsNumber ( FilteredDataLayerCount ) , FText : : AsNumber ( SelectedDataLayerCount ) ) ;
2021-01-27 13:03:11 -04:00
}
}
2021-11-07 23:43:01 -05:00
else if ( SceneOutliner - > IsTextFilterActive ( ) & & FilteredDataLayerCount = = 0 )
2021-01-27 13:03:11 -04:00
{
2021-11-07 23:43:01 -05:00
return FText : : Format ( LOCTEXT ( " ShowingNoDataLayersFmt " , " No matching data layers ({0} total) " ) , FText : : AsNumber ( TotalDataLayerCount ) ) ;
}
else if ( SelectedDataLayerCount ! = 0 )
{
return FText : : Format ( LOCTEXT ( " ShowingOnlySomeDataLayersSelectedFmt " , " Showing {0} of {1} data layers ({2} selected) " ) , FText : : AsNumber ( FilteredDataLayerCount ) , FText : : AsNumber ( TotalDataLayerCount ) , FText : : AsNumber ( SelectedDataLayerCount ) ) ;
}
else
{
return FText : : Format ( LOCTEXT ( " ShowingOnlySomeDataLayersFmt " , " Showing {0} of {1} data layers " ) , FText : : AsNumber ( FilteredDataLayerCount ) , FText : : AsNumber ( TotalDataLayerCount ) ) ;
2021-01-27 13:03:11 -04:00
}
}
2022-05-24 06:58:06 -04:00
FFolder : : FRootObject FDataLayerMode : : GetRootObject ( ) const
{
return FFolder : : GetWorldRootFolder ( RepresentingWorld . Get ( ) ) . GetRootObject ( ) ;
}
2020-10-28 06:51:40 -04:00
SDataLayerBrowser * FDataLayerMode : : GetDataLayerBrowser ( ) const
{
return DataLayerBrowser ;
}
void FDataLayerMode : : OnItemAdded ( FSceneOutlinerTreeItemPtr Item )
{
2021-11-25 13:51:47 -05:00
if ( FDataLayerTreeItem * DataLayerItem = Item - > CastTo < FDataLayerTreeItem > ( ) )
2020-10-28 06:51:40 -04:00
{
if ( ! Item - > Flags . bIsFilteredOut )
{
2021-11-07 23:43:01 -05:00
+ + FilteredDataLayerCount ;
2021-11-25 13:51:47 -05:00
if ( ShouldExpandDataLayer ( DataLayerItem - > GetDataLayer ( ) ) )
{
SceneOutliner - > SetItemExpansion ( DataLayerItem - > AsShared ( ) , true ) ;
}
2020-11-03 18:28:22 -04:00
if ( SelectedDataLayersSet . Contains ( DataLayerItem - > GetDataLayer ( ) ) )
2020-11-03 17:16:48 -04:00
{
SceneOutliner - > AddToSelection ( { Item } ) ;
}
}
}
else if ( const FDataLayerActorTreeItem * DataLayerActorTreeItem = Item - > CastTo < FDataLayerActorTreeItem > ( ) )
{
if ( SelectedDataLayerActors . Contains ( FSelectedDataLayerActor ( DataLayerActorTreeItem - > GetDataLayer ( ) , DataLayerActorTreeItem - > GetActor ( ) ) ) )
{
SceneOutliner - > AddToSelection ( { Item } ) ;
2020-10-28 06:51:40 -04:00
}
}
}
2021-11-07 23:43:01 -05:00
void FDataLayerMode : : OnItemRemoved ( FSceneOutlinerTreeItemPtr Item )
{
if ( const FDataLayerTreeItem * DataLayerItem = Item - > CastTo < FDataLayerTreeItem > ( ) )
{
if ( ! Item - > Flags . bIsFilteredOut )
{
- - FilteredDataLayerCount ;
}
}
}
void FDataLayerMode : : OnItemPassesFilters ( const ISceneOutlinerTreeItem & Item )
{
if ( const FDataLayerTreeItem * const DataLayerItem = Item . CastTo < FDataLayerTreeItem > ( ) )
{
ApplicableDataLayers . Add ( DataLayerItem - > GetDataLayer ( ) ) ;
}
}
2020-10-28 06:51:40 -04:00
void FDataLayerMode : : OnItemDoubleClick ( FSceneOutlinerTreeItemPtr Item )
{
2022-11-18 15:32:06 -05:00
if ( FDataLayerTreeItem * DataLayerItem = Item - > CastTo < FDataLayerTreeItem > ( ) )
2020-10-28 06:51:40 -04:00
{
2022-03-15 13:52:28 -04:00
if ( UDataLayerInstance * DataLayerInstance = DataLayerItem - > GetDataLayer ( ) )
2020-10-28 06:51:40 -04:00
{
2023-03-26 15:44:07 -04:00
if ( DataLayerInstance - > CanBeInActorEditorContext ( ) )
2022-11-18 15:32:06 -05:00
{
if ( ! DataLayerInstance - > IsInActorEditorContext ( ) )
{
const FScopedTransaction Transaction ( LOCTEXT ( " MakeCurrentDataLayers " , " Make Current Data Layer(s) " )) ;
2023-12-18 08:29:44 -05:00
if ( ! FSlateApplication : : Get ( ) . GetModifierKeys ( ) . IsControlDown ( ) )
{
const UDataLayerManager * DataLayerManger = UDataLayerManager : : GetDataLayerManager ( GetOwningWorld ( ) ) ;
const TArray < UDataLayerInstance * > ActorEditorContextDataLayers = DataLayerManger - > GetActorEditorContextDataLayers ( ) ;
for ( UDataLayerInstance * DataLayerInstanceIt : ActorEditorContextDataLayers )
{
UDataLayerEditorSubsystem : : Get ( ) - > RemoveFromActorEditorContext ( DataLayerInstanceIt ) ;
}
}
2022-11-18 15:32:06 -05:00
UDataLayerEditorSubsystem : : Get ( ) - > AddToActorEditorContext ( DataLayerInstance ) ;
}
else
{
const FScopedTransaction Transaction ( LOCTEXT ( " RemoveCurrentDataLayers " , " Remove Current Data Layer(s) " )) ;
2023-12-18 08:29:44 -05:00
if ( ! FSlateApplication : : Get ( ) . GetModifierKeys ( ) . IsControlDown ( ) )
{
const UDataLayerManager * DataLayerManger = UDataLayerManager : : GetDataLayerManager ( GetOwningWorld ( ) ) ;
const TArray < UDataLayerInstance * > ActorEditorContextDataLayers = DataLayerManger - > GetActorEditorContextDataLayers ( ) ;
for ( UDataLayerInstance * DataLayerInstanceIt : ActorEditorContextDataLayers )
{
2024-01-30 14:18:27 -05:00
UDataLayerEditorSubsystem : : Get ( ) - > RemoveFromActorEditorContext ( DataLayerInstanceIt ) ;
2023-12-18 08:29:44 -05:00
}
}
else
{
UDataLayerEditorSubsystem : : Get ( ) - > RemoveFromActorEditorContext ( DataLayerInstance ) ;
}
2022-11-18 15:32:06 -05:00
}
}
2020-10-28 06:51:40 -04:00
}
}
else if ( FDataLayerActorTreeItem * DataLayerActorItem = Item - > CastTo < FDataLayerActorTreeItem > ( ) )
{
if ( AActor * Actor = DataLayerActorItem - > GetActor ( ) )
{
2022-05-16 08:48:27 -04:00
const FScopedTransaction Transaction ( LOCTEXT ( " ClickingOnActor " , " Clicking on Actor in Data Layer " ) ) ;
2020-10-28 06:51:40 -04:00
GEditor - > GetSelectedActors ( ) - > Modify ( ) ;
GEditor - > SelectNone ( /*bNoteSelectionChange*/ false , true ) ;
GEditor - > SelectActor ( Actor , /*bSelected*/ true , /*bNotify*/ true , /*bSelectEvenIfHidden*/ true ) ;
GEditor - > NoteSelectionChange ( ) ;
GEditor - > MoveViewportCamerasToActor ( * Actor , /*bActiveViewportOnly*/ false ) ;
}
}
2024-02-23 08:42:17 -05:00
else if ( FDataLayerActorDescTreeItem * DataLayerActorDescItem = Item - > CastTo < FDataLayerActorDescTreeItem > ( ) )
{
GEditor - > BroadcastSelectUnloadedActors ( { DataLayerActorDescItem - > GetGuid ( ) } ) ;
}
2020-10-28 06:51:40 -04:00
}
void FDataLayerMode : : DeleteItems ( const TArray < TWeakPtr < ISceneOutlinerTreeItem > > & Items )
{
2022-03-15 13:52:28 -04:00
TArray < UDataLayerInstance * > DataLayersToDelete ;
TMap < UDataLayerInstance * , TArray < AActor * > > ActorsToRemoveFromDataLayer ;
2020-10-28 06:51:40 -04:00
for ( const TWeakPtr < ISceneOutlinerTreeItem > & Item : Items )
{
if ( FDataLayerActorTreeItem * DataLayerActorItem = Item . Pin ( ) - > CastTo < FDataLayerActorTreeItem > ( ) )
{
2022-03-15 13:52:28 -04:00
UDataLayerInstance * DataLayerInstance = DataLayerActorItem - > GetDataLayer ( ) ;
2020-10-28 06:51:40 -04:00
AActor * Actor = DataLayerActorItem - > GetActor ( ) ;
2024-01-30 14:18:27 -05:00
if ( DataLayerInstance & & ! DataLayerInstance - > IsReadOnly ( ) & & Actor )
2020-10-28 06:51:40 -04:00
{
2022-03-15 13:52:28 -04:00
ActorsToRemoveFromDataLayer . FindOrAdd ( DataLayerInstance ) . Add ( Actor ) ;
2020-10-28 06:51:40 -04:00
}
}
else if ( FDataLayerTreeItem * DataLayerItem = Item . Pin ( ) - > CastTo < FDataLayerTreeItem > ( ) )
{
2022-03-15 13:52:28 -04:00
if ( UDataLayerInstance * DataLayerInstance = DataLayerItem - > GetDataLayer ( ) )
2020-10-28 06:51:40 -04:00
{
2024-01-30 14:18:27 -05:00
if ( ! DataLayerInstance - > IsReadOnly ( ) )
2021-02-09 15:01:37 -04:00
{
2022-03-15 13:52:28 -04:00
DataLayersToDelete . Add ( DataLayerInstance ) ;
2021-02-09 15:01:37 -04:00
}
2020-10-28 06:51:40 -04:00
}
}
}
if ( ! ActorsToRemoveFromDataLayer . IsEmpty ( ) )
{
2022-05-16 08:48:27 -04:00
const FScopedTransaction Transaction ( LOCTEXT ( " RemoveActorsFromDataLayer " , " Remove Actors from Data Layer " ) ) ;
2020-10-28 06:51:40 -04:00
for ( const auto & ItPair : ActorsToRemoveFromDataLayer )
{
DataLayerEditorSubsystem - > RemoveActorsFromDataLayer ( ItPair . Value , ItPair . Key ) ;
}
}
else if ( ! DataLayersToDelete . IsEmpty ( ) )
{
2022-10-28 16:41:09 -04:00
DeleteDataLayers ( DataLayersToDelete ) ;
}
}
2021-01-27 13:03:11 -04:00
2022-10-28 16:41:09 -04:00
void FDataLayerMode : : DeleteDataLayers ( const TArray < UDataLayerInstance * > & InDataLayersToDelete )
{
2024-01-30 14:18:27 -05:00
TArray < UDataLayerInstance * > DataLayersToDelete ;
for ( UDataLayerInstance * DataLayerInstance : InDataLayersToDelete )
{
if ( DataLayerInstance - > CanBeRemoved ( ) )
{
DataLayersToDelete . Add ( DataLayerInstance ) ;
}
}
2022-10-28 16:41:09 -04:00
int32 PrevDeleteCount = SelectedDataLayersSet . Num ( ) ;
2024-01-30 14:18:27 -05:00
for ( UDataLayerInstance * DataLayerToDelete : DataLayersToDelete )
2022-10-28 16:41:09 -04:00
{
SelectedDataLayersSet . Remove ( DataLayerToDelete ) ;
}
{
2024-02-01 10:46:16 -05:00
const FScopedTransaction Transaction ( LOCTEXT ( " DeleteSelectedDataLayers " , " Delete Selected Data Layer(s) " )) ;
2024-01-30 14:18:27 -05:00
DataLayerEditorSubsystem - > DeleteDataLayers ( DataLayersToDelete ) ;
2022-10-28 16:41:09 -04:00
}
if ( ( SelectedDataLayersSet . Num ( ) ! = PrevDeleteCount ) & & DataLayerBrowser )
{
DataLayerBrowser - > OnSelectionChanged ( SelectedDataLayersSet ) ;
2020-10-28 06:51:40 -04:00
}
}
FReply FDataLayerMode : : OnKeyDown ( const FKeyEvent & InKeyEvent )
{
const FSceneOutlinerItemSelection & Selection = SceneOutliner - > GetSelection ( ) ;
// Rename key: Rename selected actors (not rebindable, because it doesn't make much sense to bind.)
if ( InKeyEvent . GetKey ( ) = = EKeys : : F2 )
{
if ( Selection . Num ( ) = = 1 )
{
FSceneOutlinerTreeItemPtr ItemToRename = Selection . SelectedItems [ 0 ] . Pin ( ) ;
if ( ItemToRename . IsValid ( ) & & CanRenameItem ( * ItemToRename ) & & ItemToRename - > CanInteract ( ) )
{
SceneOutliner - > SetPendingRenameItem ( ItemToRename ) ;
SceneOutliner - > ScrollItemIntoView ( ItemToRename ) ;
}
return FReply : : Handled ( ) ;
}
}
// F5 forces a full refresh
else if ( InKeyEvent . GetKey ( ) = = EKeys : : F5 )
{
SceneOutliner - > FullRefresh ( ) ;
return FReply : : Handled ( ) ;
}
// Delete/BackSpace keys delete selected actors
else if ( InKeyEvent . GetKey ( ) = = EKeys : : Delete | | InKeyEvent . GetKey ( ) = = EKeys : : BackSpace )
{
DeleteItems ( Selection . SelectedItems ) ;
return FReply : : Handled ( ) ;
}
2022-11-21 17:19:31 -05:00
if ( Commands - > ProcessCommandBindings ( InKeyEvent ) )
{
return FReply : : Handled ( ) ;
}
2020-10-28 06:51:40 -04:00
return FReply : : Unhandled ( ) ;
}
bool FDataLayerMode : : ParseDragDrop ( FSceneOutlinerDragDropPayload & OutPayload , const FDragDropOperation & Operation ) const
{
2022-10-26 17:33:05 -04:00
return ! GetDataLayerActorPairsFromOperation ( Operation ) . IsEmpty ( )
| | ! GetActorsFromOperation ( Operation , true ) . IsEmpty ( )
| | ! GetDataLayerInstancesFromOperation ( Operation , true ) . IsEmpty ( )
| | ! GetDataLayerAssetsFromOperation ( Operation , true ) . IsEmpty ( ) ;
2022-02-16 11:58:08 -05:00
}
2024-01-30 14:18:27 -05:00
FSceneOutlinerDragValidationInfo FDataLayerMode : : ValidateActorDrop ( const ISceneOutlinerTreeItem & DropTarget , TArray < AActor * > PayloadActors , bool bMoveOperation /*= false*/ ) const
2022-02-16 11:58:08 -05:00
{
2024-01-30 14:18:27 -05:00
// Only support dropping actors on Data Layer Instances
const FDataLayerTreeItem * DataLayerItem = DropTarget . CastTo < FDataLayerTreeItem > ( ) ;
const UDataLayerInstance * DropTargetDataLayerInstance = DataLayerItem ? GetDataLayerInstanceFromTreeItem ( DropTarget ) : nullptr ;
if ( ! DropTargetDataLayerInstance )
2022-02-16 11:58:08 -05:00
{
2024-01-30 14:18:27 -05:00
return FSceneOutlinerDragValidationInfo ( ESceneOutlinerDropCompatibility : : IncompatibleGeneric , FText ( ) ) ;
2022-02-16 11:58:08 -05:00
}
2024-01-30 14:18:27 -05:00
// Check if user can't add actors to the target Data Layer Instance
{
FText Reason ;
if ( ! DropTargetDataLayerInstance - > CanUserAddActors ( & Reason ) )
{
const FText Text = FText : : Format ( LOCTEXT ( " CantMoveOrAssignActorsToLockedDataLayer " , " Can't {0} actor(s) to Data Layer \" {1} \" : {2} " ) , bMoveOperation ? FText : : FromString ( TEXT ( " move " ) ) : FText : : FromString ( TEXT ( " assign " ) ) , FText : : FromString ( DropTargetDataLayerInstance - > GetDataLayerShortName ( ) ) , Reason ) ;
return FSceneOutlinerDragValidationInfo ( ESceneOutlinerDropCompatibility : : IncompatibleGeneric , Text ) ;
}
}
// Check if can't add one of the payload actors to the target Data Layer Instance
for ( AActor * Actor : PayloadActors )
{
FText Reason ;
if ( ! DropTargetDataLayerInstance - > CanAddActor ( Actor , & Reason ) )
{
const FText Text = FText : : Format ( LOCTEXT ( " CantMoveOrAssignActorsToDataLayer " , " Can't {0} actor(s) to Data Layer \" {1} \" : {2} " ) , bMoveOperation ? FText : : FromString ( TEXT ( " move " ) ) : FText : : FromString ( TEXT ( " assign " ) ) , FText : : FromString ( DropTargetDataLayerInstance - > GetDataLayerShortName ( ) ) , Reason ) ;
return FSceneOutlinerDragValidationInfo ( ESceneOutlinerDropCompatibility : : IncompatibleGeneric , Text ) ;
}
}
if ( ! bMoveOperation )
{
if ( GetSelectedDataLayers ( SceneOutliner ) . Num ( ) > 1 )
{
if ( SceneOutliner - > GetTree ( ) . IsItemSelected ( const_cast < ISceneOutlinerTreeItem & > ( DropTarget ) . AsShared ( ) ) )
{
return FSceneOutlinerDragValidationInfo ( ESceneOutlinerDropCompatibility : : Compatible , LOCTEXT ( " AssignToDataLayers " , " Assign to Selected Data Layers " ) ) ;
}
}
}
const FText Text = FText : : Format ( LOCTEXT ( " MoveOrAssignToDataLayer " , " {0} to Data Layer \" {1} \" " ) , bMoveOperation ? FText : : FromString ( TEXT ( " Move " ) ) : FText : : FromString ( TEXT ( " Assign " ) ) , FText : : FromString ( DropTargetDataLayerInstance - > GetDataLayerShortName ( ) ) ) ;
return FSceneOutlinerDragValidationInfo ( ESceneOutlinerDropCompatibility : : Compatible , Text ) ;
2020-10-28 06:51:40 -04:00
}
FSceneOutlinerDragValidationInfo FDataLayerMode : : ValidateDrop ( const ISceneOutlinerTreeItem & DropTarget , const FSceneOutlinerDragDropPayload & Payload ) const
{
2021-02-10 19:52:02 -04:00
TArray < AActor * > PayloadActors = GetActorsFromOperation ( Payload . SourceOperation ) ;
2022-02-16 11:58:08 -05:00
if ( ! PayloadActors . IsEmpty ( ) ) // Adding actor(s) in data layer(s)
2020-10-28 06:51:40 -04:00
{
2023-04-28 16:01:13 -04:00
const FDataLayerTreeItem * DataLayerItem = DropTarget . CastTo < FDataLayerTreeItem > ( ) ;
2024-01-30 14:18:27 -05:00
if ( UDataLayerInstance * TargetDataLayerInstance = DataLayerItem ? DataLayerItem - > GetDataLayer ( ) : nullptr )
2021-02-10 19:51:47 -04:00
{
2024-01-30 14:18:27 -05:00
const bool bIsPrivateDataLayer = TargetDataLayerInstance - > GetAsset ( ) & & TargetDataLayerInstance - > GetAsset ( ) - > IsPrivate ( ) ;
const AWorldDataLayers * OuterWorldDataLayers = TargetDataLayerInstance - > GetDirectOuterWorldDataLayers ( ) ;
for ( AActor * Actor : PayloadActors )
2021-02-10 19:51:47 -04:00
{
2024-01-30 14:18:27 -05:00
if ( ! Actor - > IsUserManaged ( ) | | ! DataLayerEditorSubsystem - > IsActorValidForDataLayerInstances ( Actor , { TargetDataLayerInstance } ) )
{
return FSceneOutlinerDragValidationInfo ( ESceneOutlinerDropCompatibility : : IncompatibleGeneric , LOCTEXT ( " ActorCantBeAssignedToDataLayer " , " Can't assign actors to Data Layer " ) ) ;
}
else if ( bIsPrivateDataLayer & & ( Actor - > GetLevel ( ) - > GetWorldDataLayers ( ) ! = OuterWorldDataLayers ) )
{
return FSceneOutlinerDragValidationInfo ( ESceneOutlinerDropCompatibility : : IncompatibleGeneric , LOCTEXT ( " ActorCantBeAssignedToPrivateDataLayerOfOtherWorldDataLayers " , " Can't assign actors to Private Data Layer of another WorldDataLayers actor " ) ) ;
}
2023-04-28 16:01:13 -04:00
}
2021-02-10 19:51:47 -04:00
}
2024-01-30 14:18:27 -05:00
return ValidateActorDrop ( DropTarget , PayloadActors ) ;
2020-10-28 06:51:40 -04:00
}
2022-10-26 17:33:05 -04:00
2024-01-30 14:18:27 -05:00
// Drag and drop actor(s) into a Data Layer Instance
2023-02-28 08:35:38 -05:00
if ( ! GetDataLayerActorPairsFromOperation ( Payload . SourceOperation ) . IsEmpty ( ) )
2022-02-16 11:58:08 -05:00
{
2024-01-30 14:18:27 -05:00
return ValidateActorDrop ( DropTarget , PayloadActors , true ) ;
2022-02-16 11:58:08 -05:00
}
2023-02-28 08:35:38 -05:00
2024-01-30 14:18:27 -05:00
// Drag and drop Data Layer Asset(s)
2021-11-07 23:43:01 -05:00
{
2023-02-28 08:35:38 -05:00
TArray < const UDataLayerAsset * > DataLayerAssets = GetDataLayerAssetsFromOperation ( Payload . SourceOperation ) ;
if ( ! DataLayerAssets . IsEmpty ( ) )
{
return ValidateDataLayerAssetDrop ( DropTarget , DataLayerAssets ) ;
}
2022-10-26 17:33:05 -04:00
}
2024-01-30 14:18:27 -05:00
// Drag and drop Data Layer Instance(s)
2022-10-26 17:33:05 -04:00
TArray < UDataLayerInstance * > PayloadDataLayers = GetDataLayerInstancesFromOperation ( Payload . SourceOperation ) ;
if ( ! PayloadDataLayers . IsEmpty ( ) )
{
2023-02-28 08:35:38 -05:00
// Drag and drop DataLayerInstance(s) from different AWorldDataLayers
AWorldDataLayers * PayloadWorldDatalayers = nullptr ;
for ( UDataLayerInstance * DataLayerInstance : PayloadDataLayers )
{
if ( ! PayloadWorldDatalayers )
{
2024-01-30 14:18:27 -05:00
PayloadWorldDatalayers = DataLayerInstance - > GetDirectOuterWorldDataLayers ( ) ;
2023-02-28 08:35:38 -05:00
}
2024-01-30 14:18:27 -05:00
else if ( PayloadWorldDatalayers ! = DataLayerInstance - > GetDirectOuterWorldDataLayers ( ) )
2023-02-28 08:35:38 -05:00
{
PayloadWorldDatalayers = nullptr ;
break ;
}
}
if ( ! PayloadWorldDatalayers )
{
return FSceneOutlinerDragValidationInfo ( ESceneOutlinerDropCompatibility : : IncompatibleGeneric , LOCTEXT ( " CantMoveMultipleDataLayersComingFromDifferentWorldDataLayers " , " Can't move multiple Data Layers coming from different WorldDataLayers " ) ) ;
}
// Drag and drop DataLayerInstanceWithAsset(s) between AWorldDataLayers
2024-01-30 14:18:27 -05:00
AWorldDataLayers * DropTargetWorldDataLayers = GetWorldDataLayersFromTreeItem ( DropTarget ) ;
2023-02-28 08:35:38 -05:00
if ( DropTargetWorldDataLayers & & ( PayloadWorldDatalayers ! = DropTargetWorldDataLayers ) )
{
TSet < const UDataLayerAsset * > DataLayerAssets ;
for ( UDataLayerInstance * DataLayerInstance : PayloadDataLayers )
{
if ( const UDataLayerInstanceWithAsset * DataLayerInstanceWithAsset = Cast < UDataLayerInstanceWithAsset > ( DataLayerInstance ) )
{
if ( const UDataLayerAsset * DataLayerAsset = DataLayerInstanceWithAsset - > GetAsset ( ) )
{
DataLayerAssets . Add ( DataLayerAsset ) ;
}
}
}
if ( ! DataLayerAssets . IsEmpty ( ) )
{
2024-03-20 08:07:32 -04:00
const bool bIsMovingDataLayerInstances = true ;
return ValidateDataLayerAssetDrop ( DropTarget , DataLayerAssets . Array ( ) , bIsMovingDataLayerInstances ) ;
2023-02-28 08:35:38 -05:00
}
return FSceneOutlinerDragValidationInfo ( ESceneOutlinerDropCompatibility : : IncompatibleGeneric , LOCTEXT ( " NoValidDataLayersToMove " , " No valid Data Layer to move " ) ) ;
}
2024-01-30 14:18:27 -05:00
const UDataLayerInstance * ParentDataLayerInstance = GetDataLayerInstanceFromTreeItem ( DropTarget ) ;
2022-10-26 17:33:05 -04:00
for ( UDataLayerInstance * DataLayerInstance : PayloadDataLayers )
{
2021-11-07 23:43:01 -05:00
{
2024-01-30 14:18:27 -05:00
FText Reason ;
if ( DataLayerInstance - > IsReadOnly ( & Reason ) )
{
return FSceneOutlinerDragValidationInfo ( ESceneOutlinerDropCompatibility : : IncompatibleGeneric , FText : : Format ( LOCTEXT ( " CantMoveReadOnlyDataLayer " , " Can't move Data Layer : {0} " ) , Reason ) ) ;
}
2021-11-07 23:43:01 -05:00
}
2024-01-30 14:18:27 -05:00
if ( ParentDataLayerInstance ! = nullptr )
2021-11-07 23:43:01 -05:00
{
2024-01-30 14:18:27 -05:00
FText Reason ;
if ( ! DataLayerInstance - > CanBeChildOf ( ParentDataLayerInstance , & Reason ) )
2022-10-26 17:33:05 -04:00
{
2024-01-30 14:18:27 -05:00
return FSceneOutlinerDragValidationInfo ( ESceneOutlinerDropCompatibility : : IncompatibleGeneric , Reason ) ;
2022-10-26 17:33:05 -04:00
}
2024-01-30 14:18:27 -05:00
if ( ParentDataLayerInstance - > IsReadOnly ( & Reason ) )
2022-10-26 17:33:05 -04:00
{
2024-01-30 14:18:27 -05:00
return FSceneOutlinerDragValidationInfo ( ESceneOutlinerDropCompatibility : : IncompatibleGeneric , FText : : Format ( LOCTEXT ( " CantMoveDataLayerToLockedDataLayer " , " Can't move to Data Layer : {0} " ) , Reason ) ) ;
2022-10-26 17:33:05 -04:00
}
2021-11-07 23:43:01 -05:00
}
}
2022-10-26 17:33:05 -04:00
2024-01-30 14:18:27 -05:00
if ( ParentDataLayerInstance )
2022-10-26 17:33:05 -04:00
{
2024-01-30 14:18:27 -05:00
return FSceneOutlinerDragValidationInfo ( ESceneOutlinerDropCompatibility : : Compatible , FText : : Format ( LOCTEXT ( " MoveDataLayerToDataLayer " , " Move to Data Layer \" {0} \" " ) , FText : : FromString ( ParentDataLayerInstance - > GetDataLayerShortName ( ) ) ) ) ;
2022-10-26 17:33:05 -04:00
}
else
{
return FSceneOutlinerDragValidationInfo ( ESceneOutlinerDropCompatibility : : Compatible , LOCTEXT ( " MoveDataLayerToRoot " , " Move to root " ) ) ;
}
2021-11-07 23:43:01 -05:00
}
2020-10-28 06:51:40 -04:00
return FSceneOutlinerDragValidationInfo : : Invalid ( ) ;
}
2024-01-30 14:18:27 -05:00
UDataLayerInstance * FDataLayerMode : : GetDataLayerInstanceFromTreeItem ( const ISceneOutlinerTreeItem & TreeItem ) const
2023-02-28 08:35:38 -05:00
{
2024-01-30 14:18:27 -05:00
const FDataLayerActorTreeItem * DataLayerActorTargetItem = TreeItem . CastTo < FDataLayerActorTreeItem > ( ) ;
const FDataLayerTreeItem * DataLayerTargetItem = TreeItem . CastTo < FDataLayerTreeItem > ( ) ;
UDataLayerInstance * DataLayerTarget = DataLayerTargetItem ? DataLayerTargetItem - > GetDataLayer ( ) : ( DataLayerActorTargetItem ? DataLayerActorTargetItem - > GetDataLayer ( ) : nullptr ) ;
return DataLayerTarget ;
}
AWorldDataLayers * FDataLayerMode : : GetWorldDataLayersFromTreeItem ( const ISceneOutlinerTreeItem & TreeItem ) const
{
AWorldDataLayers * WorldDataLayers = GetOwningWorldAWorldDataLayers ( ) ;
2023-02-28 08:35:38 -05:00
if ( const FWorldDataLayersTreeItem * WorldDataLayerTreeItem = TreeItem . CastTo < FWorldDataLayersTreeItem > ( ) )
{
WorldDataLayers = WorldDataLayerTreeItem - > GetWorldDataLayers ( ) ;
}
2024-01-30 14:18:27 -05:00
else if ( const FFolderTreeItem * FolderTreeItem = TreeItem . CastTo < FFolderTreeItem > ( ) )
2023-02-28 08:35:38 -05:00
{
2024-01-30 14:18:27 -05:00
if ( const UObject * RootObject = FolderTreeItem - > GetFolder ( ) . GetRootObjectPtr ( ) )
2023-02-28 08:35:38 -05:00
{
2024-01-30 14:18:27 -05:00
if ( AWorldDataLayers * RootObjectWorldDataLayers = RootObject - > GetWorld ( ) ? RootObject - > GetWorld ( ) - > GetWorldDataLayers ( ) : nullptr )
{
WorldDataLayers = RootObjectWorldDataLayers ;
}
2023-02-28 08:35:38 -05:00
}
}
2024-01-30 14:18:27 -05:00
else if ( const UDataLayerInstance * DataLayerTarget = GetDataLayerInstanceFromTreeItem ( TreeItem ) )
{
WorldDataLayers = DataLayerTarget - > GetDirectOuterWorldDataLayers ( ) ;
}
2023-02-28 08:35:38 -05:00
return WorldDataLayers ;
}
2024-02-23 15:55:19 -05:00
bool FDataLayerMode : : CanReferenceDataLayerAssets ( const AWorldDataLayers * InWorldDataLayers , const TArray < const UDataLayerAsset * > & InReferencedDataLayerAssets , FText * OutFailureReason ) const
{
const AWorldDataLayers * ReferencingWorldDataLayers = InWorldDataLayers ? InWorldDataLayers : GetOwningWorldAWorldDataLayers ( ) ;
for ( const UDataLayerAsset * DataLayerAsset : InReferencedDataLayerAssets )
{
if ( ! ReferencingWorldDataLayers - > CanReferenceDataLayerAsset ( DataLayerAsset , OutFailureReason ) )
{
return false ;
}
}
return true ;
}
2024-03-20 08:07:32 -04:00
FSceneOutlinerDragValidationInfo FDataLayerMode : : ValidateDataLayerAssetDrop ( const ISceneOutlinerTreeItem & DropTarget , const TArray < const UDataLayerAsset * > & DataLayerAssetsToDrop , bool bIsMovingDataLayerInstances ) const
2021-11-07 23:43:01 -05:00
{
2022-10-26 17:33:05 -04:00
check ( ! DataLayerAssetsToDrop . IsEmpty ( ) ) ;
2024-03-20 08:07:32 -04:00
const FString CreateOrMoveString ( bIsMovingDataLayerInstances ? " move " : " create " ) ;
2022-10-26 17:33:05 -04:00
if ( DataLayerEditorSubsystem - > HasDeprecatedDataLayers ( ) )
{
2024-03-20 08:07:32 -04:00
return FSceneOutlinerDragValidationInfo ( ESceneOutlinerDropCompatibility : : Incompatible , FText : : Format ( LOCTEXT ( " CantCreateOrMoveInstanceWorldHasDeprecatedDataLayers " , " Cannot {0} Data Layers Instance from assets since \" {1} \" has deprecated data layers. " ) ,
FText : : FromString ( CreateOrMoveString ) ,
2022-10-26 17:33:05 -04:00
FText : : FromString ( GetOwningWorld ( ) - > GetName ( ) ) ) ) ;
}
2024-01-30 14:18:27 -05:00
const AWorldDataLayers * DropTargetWorldDataLayers = GetWorldDataLayersFromTreeItem ( DropTarget ) ;
const UDataLayerInstance * DropTargetDataLayerInstance = GetDataLayerInstanceFromTreeItem ( DropTarget ) ;
const UDataLayerInstanceWithAsset * DropTargetDataLayerWithAsset = DropTargetDataLayerInstance ? Cast < UDataLayerInstanceWithAsset > ( DropTargetDataLayerInstance ) : nullptr ;
if ( ! DropTarget . CanInteract ( ) | | ( DropTargetDataLayerWithAsset & & DropTargetDataLayerWithAsset - > IsReadOnly ( ) ) )
2022-10-26 17:33:05 -04:00
{
return FSceneOutlinerDragValidationInfo ( ESceneOutlinerDropCompatibility : : Incompatible , FText : : Format ( LOCTEXT ( " DropTargetIsReadOnly " , " \" {0} \" is read only. " ) , FText : : FromString ( DropTarget . GetDisplayString ( ) ) ) ) ;
}
2024-01-30 14:18:27 -05:00
// Check for duplicate Data Layer Asset using Outer World's AWorldDataLayers
UWorld * OuterWorld = DropTargetWorldDataLayers - > GetTypedOuter < UWorld > ( ) ;
const AWorldDataLayers * OuterWorldDataLayers = OuterWorld - > GetWorldDataLayers ( ) ;
const TArray < const UDataLayerInstance * > ExistingDataLayerInstances = OuterWorldDataLayers - > GetDataLayerInstances ( DataLayerAssetsToDrop ) ;
if ( ! ExistingDataLayerInstances . IsEmpty ( ) )
2022-10-26 17:33:05 -04:00
{
2024-01-30 14:18:27 -05:00
TArray < FString > ExistingAssestNames ;
Algo : : Transform ( ExistingDataLayerInstances , ExistingAssestNames , [ ] ( const UDataLayerInstance * DataLayerInstance ) { return Cast < UDataLayerInstanceWithAsset > ( DataLayerInstance ) - > GetAsset ( ) - > GetName ( ) ; } ) ;
FString ExistingAssetNamesString = FString : : Join ( ExistingAssestNames , TEXT ( " , " ) ) ;
return FSceneOutlinerDragValidationInfo ( ESceneOutlinerDropCompatibility : : Incompatible , FText : : Format ( LOCTEXT ( " CantCreateDataLayerInstanceSameAsset " , " Cannot create Data Layer Instance(s) , there are already Data Layer Instance ( s ) for \ " { 0 } \ " . " ) , FText : : FromString ( ExistingAssetNamesString ) ) ) ;
}
if ( Algo : : AnyOf ( DataLayerAssetsToDrop , [ ] ( const UDataLayerAsset * DataLayerAsset ) { return DataLayerAsset & & DataLayerAsset - > IsA < UExternalDataLayerAsset > ( ) ; } ) )
{
2024-02-05 18:17:01 -05:00
// Check if External Data Layer Asset can be added
UExternalDataLayerManager * ExternalDataLayerManager = UExternalDataLayerManager : : GetExternalDataLayerManager ( OuterWorld ) ;
if ( ! ExternalDataLayerManager )
{
return FSceneOutlinerDragValidationInfo ( ESceneOutlinerDropCompatibility : : Incompatible , LOCTEXT ( " CantCreateDataLayerInstanceWithExternalDataLayerAssetNotSupported " , " Cannot create External Data Layer Instance : Partitioned world doesn't support External Data Layers. " ) ) ;
}
if ( ! GetDefault < UEditorExperimentalSettings > ( ) - > bEnableWorldPartitionExternalDataLayers )
{
return FSceneOutlinerDragValidationInfo ( ESceneOutlinerDropCompatibility : : Incompatible , LOCTEXT ( " CantCreateExternalDataLayerInstanceExperimentalFlagDisabled " , " Cannot create External Data Layer Instance : Experimental flag 'Enable World Partition External Data Layers' is disabled. " ) ) ;
}
FText InjectionFailureReason ;
if ( Algo : : AnyOf ( DataLayerAssetsToDrop , [ ExternalDataLayerManager , & InjectionFailureReason ] ( const UDataLayerAsset * DataLayerAsset ) { return DataLayerAsset & & DataLayerAsset - > IsA < UExternalDataLayerAsset > ( ) & & ! ExternalDataLayerManager - > CanInjectExternalDataLayerAsset ( Cast < UExternalDataLayerAsset > ( DataLayerAsset ) , & InjectionFailureReason ) ; } ) )
{
return FSceneOutlinerDragValidationInfo ( ESceneOutlinerDropCompatibility : : Incompatible , FText : : Format ( LOCTEXT ( " CantCreateDataLayerInstanceWithExternalDataLayerAsset " , " Cannot create External Data Layer Instance : {0} " ) , InjectionFailureReason ) ) ;
}
2024-01-30 14:18:27 -05:00
if ( DropTarget . IsA < FDataLayerTreeItem > ( ) | | DropTarget . IsA < FDataLayerActorTreeItem > ( ) )
2022-10-26 17:33:05 -04:00
{
2024-01-30 14:18:27 -05:00
return FSceneOutlinerDragValidationInfo ( ESceneOutlinerDropCompatibility : : Incompatible , FText : : Format ( LOCTEXT ( " CantCreateDataLayerInstanceUnderItem " , " Cannot create External Data Layer Instance under {0} " ) , FText : : FromString ( DropTarget . GetDisplayString ( ) ) ) ) ;
2022-10-26 17:33:05 -04:00
}
2024-01-30 14:18:27 -05:00
}
2024-02-23 15:55:19 -05:00
// Special case where we receive external data layer asset(s)
if ( Algo : : AllOf ( DataLayerAssetsToDrop , [ ] ( const UDataLayerAsset * DataLayerAsset ) { return DataLayerAsset & & DataLayerAsset - > IsA < UExternalDataLayerAsset > ( ) ; } ) )
2024-01-30 14:18:27 -05:00
{
2024-02-23 15:55:19 -05:00
// Only allow to create Data Layer Instance referencing an External Data Layer Asset if the target WorldDataLayers is the main one
if ( DropTargetWorldDataLayers = = GetOwningWorldAWorldDataLayers ( ) )
2022-10-26 17:33:05 -04:00
{
2024-02-23 15:55:19 -05:00
return FSceneOutlinerDragValidationInfo ( ESceneOutlinerDropCompatibility : : Compatible , LOCTEXT ( " CreateAllExternalDataLayerFromAssetDrop " , " Create External Data Layer Instances " ) ) ;
2022-10-26 17:33:05 -04:00
}
2024-02-23 15:55:19 -05:00
}
2024-01-30 14:18:27 -05:00
// Check if can reference Data Layer Asset
2024-02-23 15:55:19 -05:00
FText FailureReason ;
if ( ! CanReferenceDataLayerAssets ( DropTargetWorldDataLayers , DataLayerAssetsToDrop , & FailureReason ) )
2024-01-30 14:18:27 -05:00
{
2024-03-20 08:07:32 -04:00
return FSceneOutlinerDragValidationInfo ( ESceneOutlinerDropCompatibility : : Incompatible , FText : : Format ( LOCTEXT ( " CantCreateOrMoveDataLayerInstancePassFilterFailed " , " Cannot {0} Data Layer Instance: {1} " ) , FText : : FromString ( CreateOrMoveString ) , FailureReason ) ) ;
2024-01-30 14:18:27 -05:00
}
// Check if target data layer supports having dropped asset as a child
if ( DropTargetDataLayerWithAsset )
{
EDataLayerType ParentType = DropTargetDataLayerWithAsset - > GetType ( ) ;
for ( const UDataLayerAsset * DataLayerAssetToDrop : DataLayerAssetsToDrop )
{
2024-02-21 14:52:19 -05:00
FText Reason ;
2024-02-26 08:26:51 -05:00
if ( ! FDataLayerUtils : : AreDataLayerTypesCompatible ( ParentType , DataLayerAssetToDrop - > GetType ( ) , DropTargetDataLayerWithAsset - > IsA < UExternalDataLayerInstance > ( ) , & Reason ) )
2024-01-30 14:18:27 -05:00
{
2024-03-20 08:07:32 -04:00
return FSceneOutlinerDragValidationInfo ( ESceneOutlinerDropCompatibility : : Incompatible , FText : : Format ( LOCTEXT ( " CantCreateOrMoveDataLayerInstanceIncompatibleChildType " , " Cannot {0} Data Layer Instance: {1} " ) , FText : : FromString ( CreateOrMoveString ) , Reason ) ) ;
2024-01-30 14:18:27 -05:00
}
}
}
if ( DropTarget . CastTo < FDataLayerTreeItem > ( ) | | DropTarget . CastTo < FWorldDataLayersTreeItem > ( ) )
{
return FSceneOutlinerDragValidationInfo ( ESceneOutlinerDropCompatibility : : Compatible , FText : : Format ( LOCTEXT ( " CreateAllDataLayerFromAssetDropOnPart " , " Create Data Layer Instances under \" {0} \" " ) , FText : : FromString ( DropTarget . GetDisplayString ( ) ) ) ) ;
2022-10-26 17:33:05 -04:00
}
else
{
2024-01-30 14:18:27 -05:00
return FSceneOutlinerDragValidationInfo ( ESceneOutlinerDropCompatibility : : Compatible , LOCTEXT ( " CreateAllDataLayerFromAssetDrop " , " Create Data Layer Instances " ) ) ;
2022-10-26 17:33:05 -04:00
}
}
TArray < UDataLayerInstance * > FDataLayerMode : : GetDataLayerInstancesFromOperation ( const FDragDropOperation & Operation , bool bOnlyFindFirst /*= false*/ ) const
{
TArray < UDataLayerInstance * > OutDataLayerInstances ;
2021-11-07 23:43:01 -05:00
2022-10-26 17:33:05 -04:00
auto GetDataLayers = [ this , & OutDataLayerInstances ] ( const FDataLayerDragDropOp & DataLayerOp )
2021-11-07 23:43:01 -05:00
{
2023-02-28 08:35:38 -05:00
for ( const TWeakObjectPtr < UDataLayerInstance > & DragDropInfo : DataLayerOp . DataLayerInstances )
2021-11-07 23:43:01 -05:00
{
2023-02-28 08:35:38 -05:00
if ( UDataLayerInstance * DataLayerInstance = DragDropInfo . Get ( ) )
2021-11-07 23:43:01 -05:00
{
2022-10-26 17:33:05 -04:00
OutDataLayerInstances . AddUnique ( DataLayerInstance ) ;
2021-11-07 23:43:01 -05:00
}
}
} ;
if ( Operation . IsOfType < FCompositeDragDropOp > ( ) )
{
const FCompositeDragDropOp & CompositeDragDropOp = StaticCast < const FCompositeDragDropOp & > ( Operation ) ;
if ( TSharedPtr < const FDataLayerDragDropOp > DataLayerDragDropOp = CompositeDragDropOp . GetSubOp < FDataLayerDragDropOp > ( ) )
{
GetDataLayers ( * DataLayerDragDropOp ) ;
}
}
else if ( Operation . IsOfType < FDataLayerDragDropOp > ( ) )
{
const FDataLayerDragDropOp & DataLayerDragDropOp = StaticCast < const FDataLayerDragDropOp & > ( Operation ) ;
GetDataLayers ( DataLayerDragDropOp ) ;
}
2022-10-26 17:33:05 -04:00
return OutDataLayerInstances ;
}
TArray < const UDataLayerAsset * > FDataLayerMode : : GetDataLayerAssetsFromOperation ( const FDragDropOperation & InDragDrop , bool bOnlyFindFirst /* = false */ ) const
{
TArray < const UDataLayerAsset * > OutDataLayerAssets ;
TArray < FAssetData > AssetDatas = AssetUtil : : ExtractAssetDataFromDrag ( InDragDrop . AsShared ( ) ) ;
for ( const FAssetData & AssetData : AssetDatas )
{
if ( AssetData . GetClass ( ) - > IsChildOf < UDataLayerAsset > ( ) )
{
if ( UObject * Asset = AssetData . GetAsset ( ) )
{
OutDataLayerAssets . Add ( StaticCast < UDataLayerAsset * > ( Asset ) ) ;
}
}
}
return OutDataLayerAssets ;
2021-11-07 23:43:01 -05:00
}
2022-02-16 11:58:08 -05:00
TArray < FDataLayerActorMoveElement > FDataLayerMode : : GetDataLayerActorPairsFromOperation ( const FDragDropOperation & Operation ) const
{
TArray < FDataLayerActorMoveElement > Out ;
if ( Operation . IsOfType < FDataLayerActorMoveOp > ( ) )
{
const FDataLayerActorMoveOp & DataLayerActorDragOp = StaticCast < const FDataLayerActorMoveOp & > ( Operation ) ;
return DataLayerActorDragOp . DataLayerActorMoveElements ;
}
return Out ;
}
TArray < AActor * > FDataLayerMode : : GetActorsFromOperation ( const FDragDropOperation & Operation , bool bOnlyFindFirst /*= false*/ ) const
2020-10-28 06:51:40 -04:00
{
TSet < AActor * > Actors ;
auto GetActorsFromFolderOperation = [ & Actors , bOnlyFindFirst ] ( const FFolderDragDropOp & FolderOp )
{
if ( bOnlyFindFirst & & Actors . Num ( ) )
{
return ;
}
if ( UWorld * World = FolderOp . World . Get ( ) )
{
TArray < TWeakObjectPtr < AActor > > ActorsToDrop ;
2021-11-23 14:43:39 -05:00
FActorFolders : : GetWeakActorsFromFolders ( * World , FolderOp . Folders , ActorsToDrop , FolderOp . RootObject ) ;
2020-10-28 06:51:40 -04:00
for ( const auto & Actor : ActorsToDrop )
{
if ( AActor * ActorPtr = Actor . Get ( ) )
{
Actors . Add ( ActorPtr ) ;
if ( bOnlyFindFirst )
{
break ;
}
}
}
}
} ;
auto GetActorsFromActorOperation = [ & Actors , bOnlyFindFirst ] ( const FActorDragDropOp & ActorOp )
{
if ( bOnlyFindFirst & & Actors . Num ( ) )
{
return ;
}
for ( const auto & Actor : ActorOp . Actors )
{
if ( AActor * ActorPtr = Actor . Get ( ) )
{
Actors . Add ( ActorPtr ) ;
if ( bOnlyFindFirst )
{
break ;
}
}
}
} ;
2021-02-08 17:38:18 -04:00
if ( Operation . IsOfType < FActorDragDropOp > ( ) )
2020-10-28 06:51:40 -04:00
{
2021-02-08 17:38:18 -04:00
const FActorDragDropOp & ActorDragOp = StaticCast < const FActorDragDropOp & > ( Operation ) ;
GetActorsFromActorOperation ( ActorDragOp ) ;
2020-10-28 06:51:40 -04:00
}
2021-02-08 17:38:18 -04:00
if ( Operation . IsOfType < FFolderDragDropOp > ( ) )
2020-10-28 06:51:40 -04:00
{
2021-02-08 17:38:18 -04:00
const FFolderDragDropOp & FolderDragOp = StaticCast < const FFolderDragDropOp & > ( Operation ) ;
GetActorsFromFolderOperation ( FolderDragOp ) ;
}
if ( Operation . IsOfType < FCompositeDragDropOp > ( ) )
{
const FCompositeDragDropOp & CompositeDragOp = StaticCast < const FCompositeDragDropOp & > ( Operation ) ;
if ( TSharedPtr < const FActorDragDropOp > ActorSubOp = CompositeDragOp . GetSubOp < FActorDragDropOp > ( ) )
{
GetActorsFromActorOperation ( * ActorSubOp ) ;
}
if ( TSharedPtr < const FFolderDragDropOp > FolderSubOp = CompositeDragOp . GetSubOp < FFolderDragDropOp > ( ) )
{
GetActorsFromFolderOperation ( * FolderSubOp ) ;
}
2020-10-28 06:51:40 -04:00
}
return Actors . Array ( ) ;
}
void FDataLayerMode : : OnDrop ( ISceneOutlinerTreeItem & DropTarget , const FSceneOutlinerDragDropPayload & Payload , const FSceneOutlinerDragValidationInfo & ValidationInfo ) const
{
2024-01-30 14:18:27 -05:00
UDataLayerInstance * TargetDataLayerInstance = GetDataLayerInstanceFromTreeItem ( DropTarget ) ;
2021-11-07 23:43:01 -05:00
2020-11-03 17:16:48 -04:00
TArray < AActor * > ActorsToAdd = GetActorsFromOperation ( Payload . SourceOperation ) ;
2022-02-16 11:58:08 -05:00
if ( ! ActorsToAdd . IsEmpty ( ) ) // Adding actor(s) in data layer(s)
2020-10-28 06:51:40 -04:00
{
2021-11-07 23:43:01 -05:00
if ( SceneOutliner - > GetTree ( ) . IsItemSelected ( const_cast < ISceneOutlinerTreeItem & > ( DropTarget ) . AsShared ( ) ) )
2020-10-28 06:51:40 -04:00
{
2022-03-15 13:52:28 -04:00
TArray < UDataLayerInstance * > AllSelectedDataLayers = GetSelectedDataLayers ( SceneOutliner ) ;
2021-11-07 23:43:01 -05:00
if ( AllSelectedDataLayers . Num ( ) > 1 )
2020-11-03 17:16:48 -04:00
{
2022-05-16 08:48:27 -04:00
const FScopedTransaction Transaction ( LOCTEXT ( " DataLayerOutlinerAddActorsToDataLayers " , " Add Actors to Data Layers " ) ) ;
2021-11-07 23:43:01 -05:00
DataLayerEditorSubsystem - > AddActorsToDataLayers ( ActorsToAdd , AllSelectedDataLayers ) ;
return ;
2020-11-03 17:16:48 -04:00
}
2021-11-07 23:43:01 -05:00
}
2020-11-03 17:16:48 -04:00
2024-01-30 14:18:27 -05:00
if ( TargetDataLayerInstance )
2021-11-07 23:43:01 -05:00
{
2022-05-16 08:48:27 -04:00
const FScopedTransaction Transaction ( LOCTEXT ( " DataLayerOutlinerAddActorsToDataLayer " , " Add Actors to Data Layer " ) ) ;
2024-01-30 14:18:27 -05:00
DataLayerEditorSubsystem - > AddActorsToDataLayer ( ActorsToAdd , TargetDataLayerInstance ) ;
2021-11-07 23:43:01 -05:00
}
2022-10-26 17:33:05 -04:00
return ;
2021-11-07 23:43:01 -05:00
}
2022-10-26 17:33:05 -04:00
if ( Payload . SourceOperation . IsOfType < FDataLayerActorMoveOp > ( ) ) // Moving actor(s) into a Data Layer
2022-02-16 11:58:08 -05:00
{
TArray < FDataLayerActorMoveElement > ActorsToMove = GetDataLayerActorPairsFromOperation ( Payload . SourceOperation ) ;
2024-01-30 14:18:27 -05:00
if ( ! ActorsToMove . IsEmpty ( ) & & TargetDataLayerInstance )
2022-02-16 11:58:08 -05:00
{
2022-05-16 08:48:27 -04:00
const FScopedTransaction Transaction ( LOCTEXT ( " DataLayerOutlinerMoveActorsToDataLayer " , " Move Actors to Data Layer " ) ) ;
2022-02-16 11:58:08 -05:00
for ( const auto & DataLayerActorPair : ActorsToMove )
{
if ( AActor * ActorPtr = DataLayerActorPair . Key . Get ( ) )
{
2024-01-30 14:18:27 -05:00
DataLayerEditorSubsystem - > AddActorToDataLayer ( ActorPtr , TargetDataLayerInstance ) ;
2022-02-16 11:58:08 -05:00
DataLayerEditorSubsystem - > RemoveActorFromDataLayer ( ActorPtr , DataLayerActorPair . Value . Get ( ) ) ;
}
}
}
return ;
}
2022-10-26 17:33:05 -04:00
2023-02-28 08:35:38 -05:00
// Handle dropping Data Layer Asset(s)
2022-10-26 17:33:05 -04:00
TArray < const UDataLayerAsset * > DataLayerAssetToDrop = GetDataLayerAssetsFromOperation ( Payload . SourceOperation ) ;
2023-02-28 08:35:38 -05:00
if ( ! DataLayerAssetToDrop . IsEmpty ( ) )
2021-11-07 23:43:01 -05:00
{
2022-10-26 17:33:05 -04:00
OnDataLayerAssetDropped ( DataLayerAssetToDrop , DropTarget ) ;
return ;
}
2023-02-28 08:35:38 -05:00
// Handle dropping DataLayerInstance(s)
TArray < UDataLayerInstance * > DataLayerInstances = GetDataLayerInstancesFromOperation ( Payload . SourceOperation ) ;
// Handle dropping DataLayerInstanceWithAsset(s) in a different AWorldDataLayers
2024-01-30 14:18:27 -05:00
AWorldDataLayers * DropTargetWorldDataLayers = GetWorldDataLayersFromTreeItem ( DropTarget ) ;
AWorldDataLayers * PayloadWorldDatalayers = DataLayerInstances . Num ( ) ? DataLayerInstances [ 0 ] - > GetDirectOuterWorldDataLayers ( ) : nullptr ; // Validation guarantees that they are all part of the same AWorldDataLayers
2023-02-28 08:35:38 -05:00
if ( DropTargetWorldDataLayers & & ( PayloadWorldDatalayers ! = DropTargetWorldDataLayers ) )
2022-10-26 17:33:05 -04:00
{
2023-02-28 08:35:38 -05:00
TSet < const UDataLayerAsset * > DataLayerAssets ;
for ( UDataLayerInstance * DataLayerInstance : DataLayerInstances )
{
if ( const UDataLayerInstanceWithAsset * DataLayerInstanceWithAsset = Cast < UDataLayerInstanceWithAsset > ( DataLayerInstance ) )
{
DataLayerAssets . Add ( DataLayerInstanceWithAsset - > GetAsset ( ) ) ;
}
}
if ( ! DataLayerAssets . IsEmpty ( ) )
{
OnDataLayerAssetDropped ( DataLayerAssets . Array ( ) , DropTarget ) ;
return ;
}
2021-11-07 23:43:01 -05:00
}
2023-02-28 08:35:38 -05:00
// Moving DataLayerInstance(s)
2024-01-30 14:18:27 -05:00
SetParentDataLayer ( DataLayerInstances , TargetDataLayerInstance ) ;
2021-11-07 23:43:01 -05:00
}
2022-10-26 17:33:05 -04:00
void FDataLayerMode : : OnDataLayerAssetDropped ( const TArray < const UDataLayerAsset * > & DroppedDataLayerAsset , ISceneOutlinerTreeItem & DropTarget ) const
{
const FScopedTransaction Transaction ( LOCTEXT ( " DataLayerOutlinerCreateDataLayerInstanceFromAssetDrop " , " Create Data Layer Instance from Data Layer Asset Drop " ) ) ;
for ( const UDataLayerAsset * DataLayerAsset : DroppedDataLayerAsset )
{
FDataLayerCreationParameters Params ;
Params . DataLayerAsset = const_cast < UDataLayerAsset * > ( DataLayerAsset ) ;
2024-01-30 14:18:27 -05:00
Params . WorldDataLayers = GetWorldDataLayersFromTreeItem ( DropTarget ) ;
if ( UDataLayerInstance * DataLayerInstance = DataLayerEditorSubsystem - > CreateDataLayerInstance ( Params ) )
2022-10-26 17:33:05 -04:00
{
2024-01-30 14:18:27 -05:00
if ( UDataLayerInstance * ParentDataLayerInstance = GetDataLayerInstanceFromTreeItem ( DropTarget ) )
2022-10-26 17:33:05 -04:00
{
2024-01-30 14:18:27 -05:00
DataLayerEditorSubsystem - > SetParentDataLayer ( DataLayerInstance , ParentDataLayerInstance ) ;
2022-10-26 17:33:05 -04:00
}
}
}
}
2022-02-16 11:58:08 -05:00
FReply FDataLayerMode : : OnDragOverItem ( const FDragDropEvent & Event , const ISceneOutlinerTreeItem & Item ) const
{
TSharedPtr < FDragDropOperation > DragOperation = Event . GetOperation ( ) ;
if ( ! DragOperation . IsValid ( ) )
{
return FReply : : Handled ( ) ;
}
if ( DragOperation - > IsOfType < FDataLayerActorMoveOp > ( ) ) // Moving actor(s) into a Data Layer
{
DragOperation - > SetCursorOverride ( EMouseCursor : : GrabHandClosed ) ;
}
else if ( DragOperation - > IsOfType < FActorDragDropOp > ( ) ) // Adding actor(s) in data layer(s)
{
DragOperation - > SetCursorOverride ( EMouseCursor : : Default ) ;
}
return FReply : : Handled ( ) ;
}
2022-03-15 13:52:28 -04:00
void FDataLayerMode : : SetParentDataLayer ( const TArray < UDataLayerInstance * > DataLayerInstances , UDataLayerInstance * ParentDataLayer ) const
2021-11-07 23:43:01 -05:00
{
2022-03-15 13:52:28 -04:00
if ( ! DataLayerInstances . IsEmpty ( ) )
2021-11-07 23:43:01 -05:00
{
2022-03-15 13:52:28 -04:00
TArray < UDataLayerInstance * > ValidDataLayers ;
ValidDataLayers . Reserve ( DataLayerInstances . Num ( ) ) ;
for ( UDataLayerInstance * DataLayerInstance : DataLayerInstances )
2021-11-07 23:43:01 -05:00
{
2023-03-26 15:44:07 -04:00
if ( DataLayerInstance - > CanBeChildOf ( ParentDataLayer ) )
2021-11-07 23:43:01 -05:00
{
2022-03-15 13:52:28 -04:00
ValidDataLayers . Add ( DataLayerInstance ) ;
2021-11-07 23:43:01 -05:00
}
}
if ( ! ValidDataLayers . IsEmpty ( ) )
{
2022-05-16 08:48:27 -04:00
const FScopedTransaction Transaction ( LOCTEXT ( " DataLayerOutlinerChangeDataLayersParent " , " Change Data Layers Parent " ) ) ;
2024-04-15 08:01:28 -04:00
DataLayerEditorSubsystem - > SetParentDataLayerForDataLayers ( ValidDataLayers , ParentDataLayer ) ;
2020-10-28 06:51:40 -04:00
}
}
}
struct FWeakDataLayerActorSelector
{
bool operator ( ) ( const TWeakPtr < ISceneOutlinerTreeItem > & Item , TWeakObjectPtr < AActor > & DataOut ) const
{
if ( TSharedPtr < ISceneOutlinerTreeItem > ItemPtr = Item . Pin ( ) )
{
if ( FDataLayerActorTreeItem * TypedItem = ItemPtr - > CastTo < FDataLayerActorTreeItem > ( ) )
{
if ( TypedItem - > IsValid ( ) )
{
DataOut = TypedItem - > Actor ;
return true ;
}
}
}
return false ;
}
} ;
2022-02-16 11:58:08 -05:00
struct FDataLayerActorPairSelector
{
bool operator ( ) ( const TWeakPtr < ISceneOutlinerTreeItem > & Item , FDataLayerActorMoveElement & DataOut ) const
{
if ( TSharedPtr < ISceneOutlinerTreeItem > ItemPtr = Item . Pin ( ) )
{
if ( FDataLayerActorTreeItem * TypedItem = ItemPtr - > CastTo < FDataLayerActorTreeItem > ( ) )
{
if ( TypedItem - > IsValid ( ) )
{
DataOut = FDataLayerActorMoveElement ( TypedItem - > Actor . Get ( ) , TypedItem - > GetDataLayer ( ) ) ;
return true ;
}
}
}
return false ;
}
} ;
2020-10-28 06:51:40 -04:00
struct FWeakDataLayerSelector
{
2022-03-15 13:52:28 -04:00
bool operator ( ) ( const TWeakPtr < ISceneOutlinerTreeItem > & Item , TWeakObjectPtr < UDataLayerInstance > & DataOut ) const
2020-10-28 06:51:40 -04:00
{
if ( TSharedPtr < ISceneOutlinerTreeItem > ItemPtr = Item . Pin ( ) )
{
if ( FDataLayerTreeItem * TypedItem = ItemPtr - > CastTo < FDataLayerTreeItem > ( ) )
{
if ( TypedItem - > IsValid ( ) )
{
DataOut = TypedItem - > GetDataLayer ( ) ;
return true ;
}
}
}
return false ;
}
} ;
2022-02-16 11:58:08 -05:00
TSharedPtr < FDragDropOperation > FDataLayerMode : : CreateDragDropOperation ( const FPointerEvent & MouseEvent , const TArray < FSceneOutlinerTreeItemPtr > & InTreeItems ) const
2020-10-28 06:51:40 -04:00
{
FSceneOutlinerDragDropPayload DraggedObjects ( InTreeItems ) ;
2021-11-07 23:43:01 -05:00
if ( DraggedObjects . Has < FDataLayerTreeItem > ( ) )
2020-10-28 06:51:40 -04:00
{
2022-03-15 13:52:28 -04:00
TArray < TWeakObjectPtr < UDataLayerInstance > > DataLayerInstances = DraggedObjects . GetData < TWeakObjectPtr < UDataLayerInstance > > ( FWeakDataLayerSelector ( ) ) ;
2024-01-30 14:18:27 -05:00
if ( DataLayerInstances . FindByPredicate ( [ & ] ( const TWeakObjectPtr < UDataLayerInstance > & DataLayerInstance ) { return DataLayerInstance . IsValid ( ) & & DataLayerInstance - > IsReadOnly ( ) ; } ) )
2021-11-07 23:43:01 -05:00
{
return TSharedPtr < FDragDropOperation > ( ) ;
}
2020-10-28 06:51:40 -04:00
}
2021-11-07 23:43:01 -05:00
auto GetDataLayerOperation = [ & DraggedObjects ] ( )
2020-10-28 06:51:40 -04:00
{
TSharedPtr < FDataLayerDragDropOp > DataLayerOperation = MakeShareable ( new FDataLayerDragDropOp ) ;
2022-03-15 13:52:28 -04:00
TArray < TWeakObjectPtr < UDataLayerInstance > > DataLayers = DraggedObjects . GetData < TWeakObjectPtr < UDataLayerInstance > > ( FWeakDataLayerSelector ( ) ) ;
2023-02-28 08:35:38 -05:00
DataLayerOperation - > Init ( DataLayers ) ;
2020-10-28 06:51:40 -04:00
DataLayerOperation - > Construct ( ) ;
2021-11-07 23:43:01 -05:00
return DataLayerOperation ;
} ;
2020-10-28 06:51:40 -04:00
2021-11-07 23:43:01 -05:00
auto GetActorOperation = [ & DraggedObjects ] ( )
{
TSharedPtr < FActorDragDropOp > ActorOperation = MakeShareable ( new FActorDragDropOp ) ;
ActorOperation - > Init ( DraggedObjects . GetData < TWeakObjectPtr < AActor > > ( FWeakDataLayerActorSelector ( ) ) ) ;
ActorOperation - > Construct ( ) ;
return ActorOperation ;
} ;
2022-02-16 11:58:08 -05:00
auto GetActorDataLayerOperation = [ & DraggedObjects ] ( )
{
TSharedPtr < FDataLayerActorMoveOp > DataLayerActorOperation = MakeShareable ( new FDataLayerActorMoveOp ) ;
DataLayerActorOperation - > DataLayerActorMoveElements = DraggedObjects . GetData < FDataLayerActorMoveElement > ( FDataLayerActorPairSelector ( ) ) ;
DataLayerActorOperation - > Construct ( ) ;
return DataLayerActorOperation ;
} ;
2021-11-07 23:43:01 -05:00
if ( DraggedObjects . Has < FDataLayerTreeItem > ( ) & & ! DraggedObjects . Has < FDataLayerActorTreeItem > ( ) )
{
return GetDataLayerOperation ( ) ;
}
else if ( ! DraggedObjects . Has < FDataLayerTreeItem > ( ) & & DraggedObjects . Has < FDataLayerActorTreeItem > ( ) )
2022-02-16 11:58:08 -05:00
{
if ( MouseEvent . IsLeftAltDown ( ) )
{
return GetActorDataLayerOperation ( ) ;
}
else
{
return GetActorOperation ( ) ;
}
2021-11-07 23:43:01 -05:00
}
else
{
TSharedPtr < FSceneOutlinerDragDropOp > OutlinerOp = MakeShareable ( new FSceneOutlinerDragDropOp ( ) ) ;
if ( DraggedObjects . Has < FDataLayerActorTreeItem > ( ) )
{
OutlinerOp - > AddSubOp ( GetActorOperation ( ) ) ;
}
if ( DraggedObjects . Has < FDataLayerTreeItem > ( ) )
{
OutlinerOp - > AddSubOp ( GetDataLayerOperation ( ) ) ;
}
OutlinerOp - > Construct ( ) ;
return OutlinerOp ;
}
2020-10-28 06:51:40 -04:00
}
static const FName DefaultContextBaseMenuName ( " DataLayerOutliner.DefaultContextMenuBase " ) ;
static const FName DefaultContextMenuName ( " DataLayerOutliner.DefaultContextMenu " ) ;
2022-03-15 13:52:28 -04:00
TArray < UDataLayerInstance * > FDataLayerMode : : GetSelectedDataLayers ( SSceneOutliner * InSceneOutliner ) const
2020-11-03 17:16:48 -04:00
{
FSceneOutlinerItemSelection ItemSelection ( InSceneOutliner - > GetSelection ( ) ) ;
TArray < FDataLayerTreeItem * > SelectedDataLayerItems ;
ItemSelection . Get < FDataLayerTreeItem > ( SelectedDataLayerItems ) ;
2022-03-15 13:52:28 -04:00
TArray < UDataLayerInstance * > ValidSelectedDataLayers ;
2020-11-03 17:16:48 -04:00
Algo : : TransformIf ( SelectedDataLayerItems , ValidSelectedDataLayers , [ ] ( const auto Item ) { return Item & & Item - > GetDataLayer ( ) ; } , [ ] ( const auto Item ) { return Item - > GetDataLayer ( ) ; } ) ;
return MoveTemp ( ValidSelectedDataLayers ) ;
}
2024-01-30 14:18:27 -05:00
void FDataLayerMode : : CreateDataLayerPicker ( UToolMenu * InMenu , FOnDataLayerInstancePicked OnDataLayerInstancePicked , FOnShouldFilterDataLayerInstance OnShouldFilterDataLayerInstance = FOnShouldFilterDataLayerInstance ( ) , bool bInShowRoot /*= false*/ )
2021-11-07 23:43:01 -05:00
{
2024-01-30 14:18:27 -05:00
FToolMenuSection & Section = InMenu - > AddSection ( " DataLayers " , LOCTEXT ( " DataLayers " , " Data Layers " ) ) ;
2021-11-07 23:43:01 -05:00
if ( bInShowRoot )
{
2024-01-30 14:18:27 -05:00
Section . AddMenuEntry ( " Root " , LOCTEXT ( " Root " , " <Root> " ) , FText ( ) , FSlateIcon ( ) , FUIAction ( FExecuteAction : : CreateLambda ( [ = ] ( ) { OnDataLayerInstancePicked . ExecuteIfBound ( nullptr ) ; } ) ) ) ;
2021-11-07 23:43:01 -05:00
}
2024-01-30 14:18:27 -05:00
TSharedRef < SWidget > DataLayerPickerWidget = FDataLayerPickingMode : : CreateDataLayerPickerWidget ( OnDataLayerInstancePicked , OnShouldFilterDataLayerInstance ) ;
2021-11-07 23:43:01 -05:00
Section . AddEntry ( FToolMenuEntry : : InitWidget ( " DataLayerPickerWidget " , DataLayerPickerWidget , FText : : GetEmpty ( ) , false ) ) ;
}
2022-05-10 10:22:54 -04:00
UWorld * FDataLayerMode : : GetOwningWorld ( ) const
{
UWorld * World = RepresentingWorld . Get ( ) ;
return World ? World - > PersistentLevel - > GetWorld ( ) : nullptr ;
}
AWorldDataLayers * FDataLayerMode : : GetOwningWorldAWorldDataLayers ( ) const
{
UWorld * OwningWorld = GetOwningWorld ( ) ;
return OwningWorld ? OwningWorld - > GetWorldDataLayers ( ) : nullptr ;
}
2022-11-21 17:19:31 -05:00
void FDataLayerMode : : FindInContentBrowser ( )
{
if ( SceneOutliner )
{
TArray < UObject * > Objects ;
for ( TWeakObjectPtr < const UDataLayerInstance > & DataLayerInstance : SelectedDataLayersSet )
{
if ( const UDataLayerInstanceWithAsset * DataLayerInstanceWithAsset = Cast < UDataLayerInstanceWithAsset > ( DataLayerInstance . Get ( ) ) )
{
if ( const UDataLayerAsset * Asset = DataLayerInstanceWithAsset - > GetAsset ( ) )
{
Objects . Add ( const_cast < UDataLayerAsset * > ( Asset ) ) ;
}
}
}
if ( ! Objects . IsEmpty ( ) )
{
GEditor - > SyncBrowserToObjects ( Objects ) ;
}
}
}
bool FDataLayerMode : : CanFindInContentBrowser ( ) const
{
for ( const TWeakObjectPtr < const UDataLayerInstance > & DataLayerInstance : SelectedDataLayersSet )
{
if ( const UDataLayerInstanceWithAsset * DataLayerInstanceWithAsset = Cast < UDataLayerInstanceWithAsset > ( DataLayerInstance . Get ( ) ) )
{
if ( const UDataLayerAsset * Asset = DataLayerInstanceWithAsset - > GetAsset ( ) )
{
return true ;
}
}
}
return false ;
}
2020-10-28 06:51:40 -04:00
void FDataLayerMode : : RegisterContextMenu ( )
{
UToolMenus * ToolMenus = UToolMenus : : Get ( ) ;
if ( ! ToolMenus - > IsMenuRegistered ( DefaultContextBaseMenuName ) )
{
UToolMenu * Menu = ToolMenus - > RegisterMenu ( DefaultContextBaseMenuName ) ;
2023-02-16 15:59:16 -05:00
Menu - > AddDynamicSection ( " DataLayerDynamicSection " , FNewToolMenuDelegate : : CreateLambda ( [ ] ( UToolMenu * InMenu )
2020-10-28 06:51:40 -04:00
{
USceneOutlinerMenuContext * Context = InMenu - > FindContext < USceneOutlinerMenuContext > ( ) ;
if ( ! Context | | ! Context - > SceneOutliner . IsValid ( ) )
{
return ;
}
SSceneOutliner * SceneOutliner = Context - > SceneOutliner . Pin ( ) . Get ( ) ;
2022-06-17 13:03:41 -04:00
FDataLayerMode * Mode = const_cast < FDataLayerMode * > ( static_cast < const FDataLayerMode * > ( SceneOutliner - > GetMode ( ) ) ) ;
check ( Mode ) ;
TArray < UDataLayerInstance * > SelectedDataLayers = Mode - > GetSelectedDataLayers ( SceneOutliner ) ;
2024-01-30 14:18:27 -05:00
const bool bSelectedDataLayersContainsLocked = Algo : : AnyOf ( SelectedDataLayers , [ ] ( const UDataLayerInstance * DataLayerInstance ) { return DataLayerInstance - > IsReadOnly ( ) ; } ) ;
2023-10-06 13:03:20 -04:00
const bool bSelectedDataLayersContainsExternalPackage = Algo : : AnyOf ( SelectedDataLayers , [ ] ( const UDataLayerInstance * DataLayerInstance ) { return DataLayerInstance - > IsPackageExternal ( ) ; } ) ;
2023-04-11 11:30:47 -04:00
TArray < AActor * > SelectedActors ;
GEditor - > GetSelectedActors ( ) - > GetSelectedObjects < AActor > ( SelectedActors ) ;
const bool bSelectedActorsAreAllUserManaged = Algo : : AllOf ( SelectedActors , [ ] ( const AActor * Actor ) { return Actor - > IsUserManaged ( ) ; } ) ;
static const FText SelectionContainsNonUserManagedActorsText = LOCTEXT ( " SelectionContainsUserManagedActors " , " Selection Contains Non User Managed Actors " ) ;
2020-10-28 06:51:40 -04:00
2022-03-15 13:52:28 -04:00
bool bHasActorEditorContextDataLayers = false ;
TArray < const UDataLayerInstance * > AllDataLayers ;
2023-01-31 17:03:25 -05:00
if ( const UDataLayerManager * DataLayerManager = UDataLayerManager : : GetDataLayerManager ( Mode - > GetOwningWorld ( ) ) )
2020-10-28 06:51:40 -04:00
{
2023-01-31 17:03:25 -05:00
DataLayerManager - > ForEachDataLayerInstance ( [ & AllDataLayers ] ( UDataLayerInstance * DataLayerInstance )
2020-11-03 17:16:48 -04:00
{
2022-03-15 13:52:28 -04:00
AllDataLayers . Add ( DataLayerInstance ) ;
2020-11-03 17:16:48 -04:00
return true ;
} ) ;
2022-03-08 09:40:27 -05:00
2023-01-31 17:03:25 -05:00
bHasActorEditorContextDataLayers = ! DataLayerManager - > GetActorEditorContextDataLayers ( ) . IsEmpty ( ) ;
2020-10-28 06:51:40 -04:00
}
{
2021-03-17 15:17:35 -04:00
FToolMenuSection & Section = InMenu - > AddSection ( " DataLayers " , LOCTEXT ( " DataLayers " , " Data Layers " ) ) ;
2021-11-07 23:43:01 -05:00
2023-02-28 08:35:38 -05:00
auto GetBestCandidateWorldDataLayersFromSelection = [ ] ( SSceneOutliner * SceneOutliner , FDataLayerMode * Mode )
{
FSceneOutlinerItemSelection Selection ( SceneOutliner - > GetSelection ( ) ) ;
TArray < FWorldDataLayersTreeItem * > SelectedWorldDataLayersItems ;
Selection . Get < FWorldDataLayersTreeItem > ( SelectedWorldDataLayersItems ) ;
TArray < AWorldDataLayers * > SelectedDataLayers ;
Algo : : TransformIf ( SelectedWorldDataLayersItems , SelectedDataLayers , [ ] ( const FWorldDataLayersTreeItem * Item ) { return Item & & Item - > GetWorldDataLayers ( ) ; } , [ ] ( const FWorldDataLayersTreeItem * Item ) { return Item - > GetWorldDataLayers ( ) ; } ) ;
AWorldDataLayers * BestCandidate = ( SelectedDataLayers . Num ( ) = = 1 ) ? SelectedDataLayers [ 0 ] : nullptr ;
if ( ! BestCandidate )
{
TSet < AWorldDataLayers * > OuterWorldDataLayers ;
2024-01-30 14:18:27 -05:00
Algo : : TransformIf ( Mode - > SelectedDataLayersSet , OuterWorldDataLayers , [ ] ( const TWeakObjectPtr < const UDataLayerInstance > & DataLayerInstance ) { return DataLayerInstance . IsValid ( ) & & DataLayerInstance - > GetDirectOuterWorldDataLayers ( ) ; } , [ ] ( const TWeakObjectPtr < const UDataLayerInstance > & DataLayerInstance ) { return DataLayerInstance - > GetDirectOuterWorldDataLayers ( ) ; } ) ;
2023-02-28 08:35:38 -05:00
BestCandidate = ( OuterWorldDataLayers . Num ( ) = = 1 ) ? * OuterWorldDataLayers . CreateConstIterator ( ) : nullptr ;
}
if ( ! BestCandidate )
{
TSet < AWorldDataLayers * > OuterWorldDataLayers ;
2024-01-30 14:18:27 -05:00
Algo : : TransformIf ( Mode - > SelectedDataLayerActors , OuterWorldDataLayers , [ ] ( const FSelectedDataLayerActor & DataLayerActor ) { return DataLayerActor . Key . IsValid ( ) & & DataLayerActor . Key - > GetDirectOuterWorldDataLayers ( ) ; } , [ ] ( const FSelectedDataLayerActor & DataLayerActor ) { return DataLayerActor . Key - > GetDirectOuterWorldDataLayers ( ) ; } ) ;
2023-02-28 08:35:38 -05:00
BestCandidate = ( OuterWorldDataLayers . Num ( ) = = 1 ) ? * OuterWorldDataLayers . CreateConstIterator ( ) : nullptr ;
}
if ( ! BestCandidate )
{
BestCandidate = Mode - > GetOwningWorldAWorldDataLayers ( ) ;
}
return BestCandidate ;
} ;
2024-01-30 14:18:27 -05:00
auto CreateNewDataLayerInternal = [ & GetBestCandidateWorldDataLayersFromSelection , SceneOutliner , Mode ] ( const UDataLayerAsset * InDataLayerAsset = nullptr , bool bInIsPrivate = false ) - > UDataLayerInstance *
2021-11-07 23:43:01 -05:00
{
2022-06-17 13:34:04 -04:00
const FScopedTransaction Transaction ( LOCTEXT ( " CreateNewDataLayer " , " Create New Data Layer " ) ) ;
2023-02-28 08:35:38 -05:00
AWorldDataLayers * TargetWorldDataLayers = GetBestCandidateWorldDataLayersFromSelection ( SceneOutliner , Mode ) ;
2022-06-17 13:34:04 -04:00
Mode - > SelectedDataLayersSet . Empty ( ) ;
Mode - > SelectedDataLayerActors . Empty ( ) ;
FDataLayerCreationParameters CreationParams ;
CreationParams . DataLayerAsset = const_cast < UDataLayerAsset * > ( InDataLayerAsset ) ;
2024-01-30 14:18:27 -05:00
CreationParams . WorldDataLayers = TargetWorldDataLayers ;
2023-03-28 12:23:16 -04:00
CreationParams . bIsPrivate = bInIsPrivate ;
2022-06-17 13:34:04 -04:00
if ( UDataLayerInstance * NewDataLayerInstance = UDataLayerEditorSubsystem : : Get ( ) - > CreateDataLayerInstance ( CreationParams ) )
2021-11-07 23:43:01 -05:00
{
2022-06-17 13:34:04 -04:00
Mode - > SelectedDataLayersSet . Add ( NewDataLayerInstance ) ;
// Select it and open a rename when it gets refreshed
SceneOutliner - > OnItemAdded ( NewDataLayerInstance , SceneOutliner : : ENewItemAction : : Select | SceneOutliner : : ENewItemAction : : Rename ) ;
2022-10-03 21:34:17 -04:00
return NewDataLayerInstance ;
2022-05-10 10:22:54 -04:00
}
2022-10-03 21:34:17 -04:00
return nullptr ;
2022-06-17 13:34:04 -04:00
} ;
2022-05-10 10:22:54 -04:00
2023-03-28 12:23:16 -04:00
auto CreateNewDataLayer = [ SceneOutliner , Mode , CreateNewDataLayerInternal ] ( UDataLayerInstance * InParentDataLayer = nullptr , const UDataLayerAsset * InDataLayerAsset = nullptr , bool bInIsPrivate = false ) - > UDataLayerInstance *
2022-06-17 13:34:04 -04:00
{
if ( UDataLayerEditorSubsystem : : Get ( ) - > HasDeprecatedDataLayers ( ) )
2022-05-10 10:22:54 -04:00
{
2022-10-03 21:34:17 -04:00
check ( InDataLayerAsset = = nullptr ) ;
2024-01-30 14:18:27 -05:00
return CreateNewDataLayerInternal ( nullptr , false ) ;
2022-06-17 13:34:04 -04:00
}
else
{
2024-01-30 14:18:27 -05:00
return CreateNewDataLayerInternal ( InDataLayerAsset , bInIsPrivate ) ;
2021-11-07 23:43:01 -05:00
}
} ;
2024-01-30 14:18:27 -05:00
auto CreateNewEmptyDataLayer = [ SceneOutliner , Mode , CreateNewDataLayerInternal ] ( bool bInIsPrivate = false ) - > UDataLayerInstance *
2022-10-03 21:34:17 -04:00
{
2024-01-30 14:18:27 -05:00
return CreateNewDataLayerInternal ( nullptr , bInIsPrivate ) ;
2022-10-03 21:34:17 -04:00
} ;
2023-10-06 14:34:17 -04:00
2024-02-23 15:55:19 -05:00
const AWorldDataLayers * OwningWorldAWorldDataLayers = Mode - > GetOwningWorldAWorldDataLayers ( ) ;
if ( OwningWorldAWorldDataLayers & & ! OwningWorldAWorldDataLayers - > HasDeprecatedDataLayers ( ) )
2023-10-06 14:34:17 -04:00
{
2024-02-23 15:55:19 -05:00
const AWorldDataLayers * TargetWorldDataLayers = GetBestCandidateWorldDataLayersFromSelection ( SceneOutliner , Mode ) ;
2023-10-10 14:20:49 -04:00
Section . AddSubMenu ( " CreateNewDataLayerWithAsset " , LOCTEXT ( " CreateNewDataLayerWithAssetSubMenu " , " Create New Data Layer With Asset " ) , LOCTEXT ( " CreateNewDataLayerWithAssetSubMenu_ToolTip " , " Create New Data Layer With Asset " ) ,
2024-02-23 15:55:19 -05:00
FNewToolMenuDelegate : : CreateLambda ( [ Mode , CreateNewDataLayer , OwningWorldAWorldDataLayers , TargetWorldDataLayers ] ( UToolMenu * InSubMenu )
2023-10-06 14:34:17 -04:00
{
const bool bAllowClear = false ;
const bool bAllowCopyPaste = false ;
const TArray < const UClass * > AllowedClasses = { UDataLayerAsset : : StaticClass ( ) } ;
2024-01-30 14:18:27 -05:00
const TArray < const UClass * > NewAssetDisallowedClasses = { UExternalDataLayerAsset : : StaticClass ( ) } ;
2023-10-06 14:34:17 -04:00
FToolMenuSection & Section = InSubMenu - > AddSection ( " Data Layer Asset " ) ;
TSharedRef < SWidget > MenuWidget = PropertyCustomizationHelpers : : MakeAssetPickerWithMenu (
FAssetData ( ) ,
bAllowClear ,
bAllowCopyPaste ,
AllowedClasses ,
2024-01-30 14:18:27 -05:00
PropertyCustomizationHelpers : : GetNewAssetFactoriesForClasses ( AllowedClasses , NewAssetDisallowedClasses ) ,
2024-02-23 15:55:19 -05:00
FOnShouldFilterAsset : : CreateLambda ( [ Mode , OwningWorldAWorldDataLayers , TargetWorldDataLayers ] ( const FAssetData & InAssetData )
2023-10-06 14:34:17 -04:00
{
2024-01-30 14:18:27 -05:00
const UDataLayerAsset * DataLayerAsset = Cast < UDataLayerAsset > ( InAssetData . GetAsset ( ) ) ;
const UExternalDataLayerAsset * ExternalDataLayerAsset = Cast < UExternalDataLayerAsset > ( DataLayerAsset ) ;
2024-02-23 15:55:19 -05:00
// Filter all External Data Layer Assets except if the target WorldDataLayers is the main one
if ( ExternalDataLayerAsset & & ( TargetWorldDataLayers ! = OwningWorldAWorldDataLayers ) )
{
return true ;
}
// Skip asset filtering for External Data Layer asset if target WorldDataLayers is the main one
if ( ! ExternalDataLayerAsset | | ( TargetWorldDataLayers ! = OwningWorldAWorldDataLayers ) )
{
if ( ! Mode - > CanReferenceDataLayerAssets ( TargetWorldDataLayers , { DataLayerAsset } ) )
{
return true ;
}
}
// Filter already used Data Layers Assets and External Data Layer Assets that can't be added (those already added or not part of a registered GFD action)
const UExternalDataLayerManager * ExternalDataLayerManager = UExternalDataLayerManager : : GetExternalDataLayerManager ( Mode - > GetOwningWorld ( ) ) ;
2024-01-30 14:18:27 -05:00
const bool bCanInjectExternalDataLayerAsset = ExternalDataLayerAsset & & ExternalDataLayerManager & & ExternalDataLayerManager - > CanInjectExternalDataLayerAsset ( ExternalDataLayerAsset ) ;
2024-02-23 15:55:19 -05:00
return ! DataLayerAsset | | ( ExternalDataLayerAsset & & ! bCanInjectExternalDataLayerAsset ) | | OwningWorldAWorldDataLayers - > GetDataLayerInstance ( DataLayerAsset ) ;
2023-10-06 14:34:17 -04:00
} ) ,
FOnAssetSelected : : CreateLambda ( [ CreateNewDataLayer ] ( const FAssetData & InAssetData )
{
if ( UDataLayerAsset * DataLayerAsset = Cast < UDataLayerAsset > ( InAssetData . GetAsset ( ) ) )
{
CreateNewDataLayer ( nullptr , DataLayerAsset ) ;
}
} ) ,
FSimpleDelegate : : CreateLambda ( [ ] ( ) { FSlateApplication : : Get ( ) . DismissAllMenus ( ) ; } ) ) ;
Section . AddEntry ( FToolMenuEntry : : InitWidget ( " PickDataLayerAsset " , MenuWidget , FText : : GetEmpty ( ) , false ) ) ;
} ) ) ;
}
else
{
Section . AddMenuEntry ( " CreateNewDataLayer " , LOCTEXT ( " CreateNewDataLayer " , " Create New Data Layer " ) , FText ( ) , FSlateIcon ( ) ,
FUIAction ( FExecuteAction : : CreateLambda ( [ CreateNewEmptyDataLayer ] ( ) { CreateNewEmptyDataLayer ( ) ; } ) ) ) ;
}
2024-01-30 14:18:27 -05:00
2023-03-28 12:23:16 -04:00
Section . AddMenuEntry ( " CreateNewDataLayerPrivate " , LOCTEXT ( " CreateNewDataLayerPrivate " , " Create New Private Data Layer " ) , LOCTEXT ( " CreateNewDataLayerPrivateToolTip " , " Creates an Editor Only Data Layer that cannot be used by other Worlds. " ) , FSlateIcon ( ) ,
FUIAction (
2024-01-30 14:18:27 -05:00
FExecuteAction : : CreateLambda ( [ CreateNewEmptyDataLayer ] ( ) { CreateNewEmptyDataLayer ( true ) ; } ) ,
2023-03-28 12:23:16 -04:00
FCanExecuteAction ( ) ,
FIsActionChecked ( ) ,
FIsActionButtonVisible : : CreateLambda ( [ ] ( ) { return ! UDataLayerEditorSubsystem : : Get ( ) - > HasDeprecatedDataLayers ( ) ; } ) ) ) ;
2021-11-07 23:43:01 -05:00
2024-01-30 14:18:27 -05:00
const bool bAllSelectedDataLayersCanBeRemoved = Algo : : AllOf ( SelectedDataLayers , [ ] ( const UDataLayerInstance * DataLayerInstance ) { return DataLayerInstance - > CanBeRemoved ( ) ; } ) ;
Section . AddMenuEntry ( " DeleteSelectedDataLayers " , LOCTEXT ( " DeleteSelectedDataLayers " , " Delete Selected Data Layer(s) " ) , FText ( ) , FSlateIcon ( ) ,
2020-10-28 06:51:40 -04:00
FUIAction (
2024-01-30 14:18:27 -05:00
FExecuteAction : : CreateLambda ( [ Mode , SelectedDataLayers ] ( )
{
check ( ! SelectedDataLayers . IsEmpty ( ) ) ;
Mode - > DeleteDataLayers ( SelectedDataLayers ) ;
} ) ,
FCanExecuteAction : : CreateLambda ( [ SelectedDataLayers , bSelectedDataLayersContainsLocked , bAllSelectedDataLayersCanBeRemoved ]
{
return ! SelectedDataLayers . IsEmpty ( ) & & ! bSelectedDataLayersContainsLocked & & bAllSelectedDataLayersCanBeRemoved ;
} )
) ) ;
const bool bSelectedDataLayersSupportParenting = Algo : : AllOf ( SelectedDataLayers , [ ] ( const UDataLayerInstance * DataLayerInstance ) { return ! DataLayerInstance - > IsReadOnly ( ) & & DataLayerInstance - > CanHaveParentDataLayerInstance ( ) ; } ) ;
if ( ! SelectedDataLayers . IsEmpty ( ) & & ! bSelectedDataLayersContainsLocked & & bSelectedDataLayersSupportParenting )
{
Section . AddSubMenu ( " MoveSelectedDataLayersTo " , LOCTEXT ( " MoveSelectedDataLayersTo " , " Move Selected Data Layer(s) To " ) , FText ( ) ,
FNewToolMenuDelegate : : CreateLambda ( [ Mode , SelectedDataLayers ] ( UToolMenu * InSubMenu )
{
2024-06-28 07:49:02 -04:00
const bool bShowRoot = Algo : : AllOf ( SelectedDataLayers , [ ] ( const UDataLayerInstance * DataLayerInstance ) { return DataLayerInstance - > CanBeChildOf ( nullptr ) ; } ) ;
2024-01-30 14:18:27 -05:00
CreateDataLayerPicker ( InSubMenu ,
FOnDataLayerInstancePicked : : CreateLambda ( [ Mode , SelectedDataLayers ] ( UDataLayerInstance * TargetDataLayerInstance )
{
TArray < UDataLayerInstance * > DataLayerInstances ;
for ( UDataLayerInstance * DataLayerInstance : SelectedDataLayers )
{
2024-06-28 07:49:02 -04:00
if ( DataLayerInstance - > CanBeChildOf ( TargetDataLayerInstance ) )
2024-01-30 14:18:27 -05:00
{
DataLayerInstances . Add ( DataLayerInstance ) ;
}
}
Mode - > SetParentDataLayer ( DataLayerInstances , TargetDataLayerInstance ) ;
} ) ,
FOnShouldFilterDataLayerInstance : : CreateLambda ( [ Mode , SelectedDataLayers ] ( const UDataLayerInstance * InCandidateDataLayerInstance )
{
for ( UDataLayerInstance * DataLayerInstance : SelectedDataLayers )
{
if ( ! DataLayerInstance - > CanBeChildOf ( InCandidateDataLayerInstance ) )
{
2024-03-11 11:38:41 -04:00
// True means should filter
return true ;
2024-01-30 14:18:27 -05:00
}
}
2024-03-11 11:38:41 -04:00
return false ;
2024-01-30 14:18:27 -05:00
} ) ,
2024-06-28 07:49:02 -04:00
bShowRoot ) ;
2024-01-30 14:18:27 -05:00
} ) ) ;
}
Section . AddMenuEntry ( " Copy Selected Data Layer Instances(s) File Path " , LOCTEXT ( " CopySelectedDataLayerInstancessFilePath " , " Copy Selected Data Layer Instance(s) File Path " ) , FText ( ) , FSlateIcon ( ) ,
FUIAction (
FExecuteAction : : CreateLambda ( [ SelectedDataLayers ] ( )
2023-03-26 15:44:07 -04:00
{
2020-10-28 06:51:40 -04:00
check ( ! SelectedDataLayers . IsEmpty ( ) ) ;
{
2024-01-30 14:18:27 -05:00
TArray < const UObject * > Objects ;
Algo : : Transform ( SelectedDataLayers , Objects , [ ] ( UDataLayerInstance * DataLayerInstance ) { return DataLayerInstance ; } ) ;
FExternalPackageHelper : : CopyObjectsExternalPackageFilePathToClipboard ( Objects ) ;
}
} ) ,
FCanExecuteAction : : CreateLambda ( [ bSelectedDataLayersContainsExternalPackage ] { return bSelectedDataLayersContainsExternalPackage ; } )
) ) ;
Section . AddSeparator ( " SectionsSeparator " ) ;
const bool bAllSelectedDataLayersCanAddActors = Algo : : AllOf ( SelectedDataLayers , [ ] ( const UDataLayerInstance * DataLayerInstance ) { return DataLayerInstance - > CanUserAddActors ( ) ; } ) ;
FText AddActorToolTip = bSelectedActorsAreAllUserManaged ? FText : : GetEmpty ( ) : SelectionContainsNonUserManagedActorsText ;
2024-02-01 10:46:16 -05:00
Section . AddMenuEntry ( " AddSelectedActorsToSelectedDataLayers " , LOCTEXT ( " AddSelectedActorsToSelectedDataLayers " , " Add Selected Actor(s) to Selected Data Layer(s) " ) , AddActorToolTip , FSlateIcon ( ) ,
2024-01-30 14:18:27 -05:00
FUIAction (
FExecuteAction : : CreateLambda ( [ SelectedDataLayers ] ( )
{
check ( ! SelectedDataLayers . IsEmpty ( ) ) ;
{
const FScopedTransaction Transaction ( LOCTEXT ( " AddSelectedActorsToSelectedDataLayers " , " Add Selected Actor(s) to Selected Data Layer ( s ) " )) ;
2022-06-17 13:03:41 -04:00
UDataLayerEditorSubsystem : : Get ( ) - > AddSelectedActorsToDataLayers ( SelectedDataLayers ) ;
2023-03-26 15:44:07 -04:00
}
} ) ,
2023-04-11 11:30:47 -04:00
FCanExecuteAction : : CreateLambda ( [ SelectedDataLayers , bAllSelectedDataLayersCanAddActors , bSelectedActorsAreAllUserManaged ]
2024-01-30 14:18:27 -05:00
{
2023-04-11 11:30:47 -04:00
return ! SelectedDataLayers . IsEmpty ( ) & & GEditor - > GetSelectedActorCount ( ) > 0 & & bAllSelectedDataLayersCanAddActors & & bSelectedActorsAreAllUserManaged ;
} )
2020-12-03 12:41:42 -04:00
) ) ;
2020-10-28 06:51:40 -04:00
2022-06-17 13:03:41 -04:00
if ( ! Mode - > SelectedDataLayerActors . IsEmpty ( ) )
2021-11-07 23:43:01 -05:00
{
2024-01-30 14:18:27 -05:00
Section . AddSubMenu ( " AddSelectedActorsTo " , LOCTEXT ( " AddSelectedActorsTo " , " Add Selected Actor(s) To " ) , FText ( ) ,
2022-06-17 13:03:41 -04:00
FNewToolMenuDelegate : : CreateLambda ( [ Mode ] ( UToolMenu * InSubMenu )
2021-11-07 23:43:01 -05:00
{
2024-01-30 14:18:27 -05:00
CreateDataLayerPicker ( InSubMenu ,
FOnDataLayerInstancePicked : : CreateLambda ( [ Mode ] ( UDataLayerInstance * TargetDataLayer )
2021-11-07 23:43:01 -05:00
{
2024-01-30 14:18:27 -05:00
check ( TargetDataLayer ) ;
TArray < AActor * > Actors ;
Algo : : TransformIf ( Mode - > SelectedDataLayerActors , Actors , [ ] ( const FSelectedDataLayerActor & InActor ) { return InActor . Value . Get ( ) ; } , [ ] ( const FSelectedDataLayerActor & InActor ) { return const_cast < AActor * > ( InActor . Value . Get ( ) ) ; } ) ;
if ( ! Actors . IsEmpty ( ) )
2021-11-07 23:43:01 -05:00
{
2024-01-30 14:18:27 -05:00
const FScopedTransaction Transaction ( LOCTEXT ( " AddSelectedActorsToDataLayer " , " Add Selected Actors to Selected Data Layer " ) ) ;
UDataLayerEditorSubsystem : : Get ( ) - > AddActorsToDataLayers ( Actors , { TargetDataLayer } ) ;
2021-11-07 23:43:01 -05:00
}
2024-01-30 14:18:27 -05:00
} ) ,
FOnShouldFilterDataLayerInstance : : CreateLambda ( [ Mode ] ( const UDataLayerInstance * InCandidateDataLayerInstance )
{
for ( auto & [ DataLayerInstance , SelectedActor ] : Mode - > SelectedDataLayerActors )
{
if ( ! InCandidateDataLayerInstance - > CanAddActor ( const_cast < AActor * > ( SelectedActor . Get ( ) ) ) )
{
2024-03-11 11:38:41 -04:00
// True means should filter
return true ;
2024-01-30 14:18:27 -05:00
}
}
2024-03-11 11:38:41 -04:00
return false ;
2024-01-30 14:18:27 -05:00
} )
) ;
2021-11-07 23:43:01 -05:00
} ) ) ;
}
2023-04-11 11:30:47 -04:00
const bool bAllSelectedDataLayersCanRemoveActors = Algo : : AllOf ( SelectedDataLayers , [ ] ( const UDataLayerInstance * DataLayerInstance ) { return DataLayerInstance - > CanUserRemoveActors ( ) ; } ) ;
FText RemoveActorToolTip = bSelectedActorsAreAllUserManaged ? FText : : GetEmpty ( ) : SelectionContainsNonUserManagedActorsText ;
2024-01-30 14:18:27 -05:00
Section . AddMenuEntry ( " RemoveSelectedActorsFromSelectedDataLayers " , LOCTEXT ( " RemoveSelectedActorsFromSelectedDataLayersMenu " , " Remove Selected Actor(s) from Selected Data Layer(s) " ) , RemoveActorToolTip , FSlateIcon ( ) ,
2020-10-28 06:51:40 -04:00
FUIAction (
2023-04-11 11:30:47 -04:00
FExecuteAction : : CreateLambda ( [ SelectedDataLayers ] ( )
{
2020-10-28 06:51:40 -04:00
check ( ! SelectedDataLayers . IsEmpty ( ) ) ;
{
2022-05-16 08:48:27 -04:00
const FScopedTransaction Transaction ( LOCTEXT ( " RemoveSelectedActorsFromSelectedDataLayers_DataLayerMode " , " Remove Selected Actors from Selected Data Layers " ) ) ;
2022-06-17 13:03:41 -04:00
UDataLayerEditorSubsystem : : Get ( ) - > RemoveSelectedActorsFromDataLayers ( SelectedDataLayers ) ;
2023-04-11 11:30:47 -04:00
}
} ) ,
FCanExecuteAction : : CreateLambda ( [ SelectedDataLayers , bAllSelectedDataLayersCanRemoveActors , bSelectedActorsAreAllUserManaged ]
{
return ! SelectedDataLayers . IsEmpty ( ) & & GEditor - > GetSelectedActorCount ( ) > 0 & & bAllSelectedDataLayersCanRemoveActors & & bSelectedActorsAreAllUserManaged ;
} )
2020-12-03 12:41:42 -04:00
) ) ;
2020-10-28 06:51:40 -04:00
2022-11-24 12:32:40 -05:00
if ( UDataLayerEditorSubsystem : : Get ( ) - > HasDeprecatedDataLayers ( ) )
{
Section . AddMenuEntry ( " RenameSelectedDataLayer " , LOCTEXT ( " RenameSelectedDataLayer " , " Rename Selected Data Layer " ) , FText ( ) , FSlateIcon ( ) ,
FUIAction (
FExecuteAction : : CreateLambda ( [ Mode , SceneOutliner , SelectedDataLayers ] ( ) {
2024-01-30 14:18:27 -05:00
if ( SelectedDataLayers . Num ( ) = = 1 )
{
FSceneOutlinerTreeItemPtr ItemToRename = SceneOutliner - > GetTreeItem ( SelectedDataLayers [ 0 ] ) ;
if ( ItemToRename . IsValid ( ) & & Mode - > CanRenameItem ( * ItemToRename ) & & ItemToRename - > CanInteract ( ) )
2020-10-28 06:51:40 -04:00
{
2024-01-30 14:18:27 -05:00
SceneOutliner - > SetPendingRenameItem ( ItemToRename ) ;
SceneOutliner - > ScrollItemIntoView ( ItemToRename ) ;
}
} } ) ,
FCanExecuteAction : : CreateLambda ( [ SelectedDataLayers ] { return ( SelectedDataLayers . Num ( ) = = 1 ) & & ! SelectedDataLayers [ 0 ] - > IsReadOnly ( ) ; } )
2022-11-24 12:32:40 -05:00
) ) ;
}
2020-10-28 06:51:40 -04:00
Section . AddSeparator ( " SectionsSeparator " ) ;
}
{
FToolMenuSection & Section = InMenu - > AddSection ( " DataLayerSelection " , LOCTEXT ( " DataLayerSelection " , " Selection " ) ) ;
2024-01-30 14:18:27 -05:00
Section . AddMenuEntry ( " SelectActorsInDataLayers " , LOCTEXT ( " SelectActorsInDataLayers " , " Select Actor(s) in Data Layer(s) " ) , FText ( ) , FSlateIcon ( ) ,
2020-10-28 06:51:40 -04:00
FUIAction (
2022-06-17 13:03:41 -04:00
FExecuteAction : : CreateLambda ( [ SelectedDataLayers ] ( ) {
2024-01-30 14:18:27 -05:00
check ( ! SelectedDataLayers . IsEmpty ( ) ) ;
{
2024-02-01 10:46:16 -05:00
const FScopedTransaction Transaction ( LOCTEXT ( " SelectActorsInDataLayers " , " Select Actor(s) in Data Layer ( s ) " )) ;
2024-01-30 14:18:27 -05:00
GEditor - > SelectNone ( /*bNoteSelectionChange*/ false , /*bDeselectBSPSurfs*/ true ) ;
UDataLayerEditorSubsystem : : Get ( ) - > SelectActorsInDataLayers ( SelectedDataLayers , /*bSelect*/ true , /*bNotify*/ true , /*bSelectEvenIfHidden*/ true ) ;
} } ) ,
2021-11-07 23:43:01 -05:00
FCanExecuteAction : : CreateLambda ( [ SelectedDataLayers ] { return ! SelectedDataLayers . IsEmpty ( ) ; } )
2020-12-03 12:41:42 -04:00
) ) ;
2020-10-28 06:51:40 -04:00
2024-01-30 14:18:27 -05:00
Section . AddMenuEntry ( " AddActorsToSelection " , LOCTEXT ( " AddActorsToSelection " , " Add Actors in Data Layer(s) to Selection " ) , FText ( ) , FSlateIcon ( ) ,
2020-10-28 06:51:40 -04:00
FUIAction (
2022-06-17 13:03:41 -04:00
FExecuteAction : : CreateLambda ( [ SelectedDataLayers ] ( ) {
2024-01-30 14:18:27 -05:00
check ( ! SelectedDataLayers . IsEmpty ( ) ) ;
{
const FScopedTransaction Transaction ( LOCTEXT ( " AppendActorsToSelection " , " Append Actors in Data Layer to Selection " ) ) ;
UDataLayerEditorSubsystem : : Get ( ) - > SelectActorsInDataLayers ( SelectedDataLayers , /*bSelect*/ true , /*bNotify*/ true , /*bSelectEvenIfHidden*/ true ) ;
} } ) ,
2021-11-07 23:43:01 -05:00
FCanExecuteAction : : CreateLambda ( [ SelectedDataLayers ] { return ! SelectedDataLayers . IsEmpty ( ) ; } )
) ) ;
2023-10-06 13:03:20 -04:00
2024-01-30 14:18:27 -05:00
Section . AddMenuEntry ( " DeselectActors " , LOCTEXT ( " DeselectActors " , " Deselect Actor(s) in Data Layer(s) " ) , FText ( ) , FSlateIcon ( ) ,
2023-10-06 13:03:20 -04:00
FUIAction (
FExecuteAction : : CreateLambda ( [ SelectedDataLayers ] ( ) {
2024-01-30 14:18:27 -05:00
check ( ! SelectedDataLayers . IsEmpty ( ) ) ;
{
2024-02-01 10:46:16 -05:00
const FScopedTransaction Transaction ( LOCTEXT ( " DeselectActors " , " Deselect Actor(s) in Data Layer ( s ) " )) ;
2024-01-30 14:18:27 -05:00
UDataLayerEditorSubsystem : : Get ( ) - > SelectActorsInDataLayers ( SelectedDataLayers , /*bSelect*/ false , /*bNotifySelectActors*/ true ) ;
} } ) ,
FCanExecuteAction : : CreateLambda ( [ SelectedDataLayers ] { return ! SelectedDataLayers . IsEmpty ( ) ; } )
2023-10-06 13:03:20 -04:00
) ) ;
2021-11-07 23:43:01 -05:00
}
2024-02-23 08:42:17 -05:00
{
FToolMenuSection & Section = InMenu - > AddSection ( " DataLayerLoading " , LOCTEXT ( " DataLayerLoading " , " Loading " ) ) ;
2024-06-05 14:17:46 -04:00
Section . AddMenuEntry ( " ForceLoadActorsInDataLayers " , LOCTEXT ( " ForceLoadActorsInDataLayers " , " Force Load Actor(s) in Data Layer(s) " ) , FText ( ) , FSlateIcon ( ) ,
2024-02-23 08:42:17 -05:00
FUIAction (
FExecuteAction : : CreateLambda ( [ SelectedDataLayers ] ( )
{
check ( ! SelectedDataLayers . IsEmpty ( ) ) ;
2024-06-05 14:17:46 -04:00
const FScopedTransaction Transaction ( LOCTEXT ( " ForceLoadActorsInDataLayers " , " Force Load Actor(s) in Data Layer ( s ) " )) ;
2024-02-23 08:42:17 -05:00
UDataLayerEditorSubsystem : : Get ( ) - > SetActorsPinStateInDataLayers ( SelectedDataLayers , true ) ;
} ) ,
FCanExecuteAction : : CreateLambda ( [ SelectedDataLayers ] { return ! SelectedDataLayers . IsEmpty ( ) ; } )
) ) ;
2024-06-05 14:17:46 -04:00
Section . AddMenuEntry ( " ReleaseForceLoadActorsInDataLayers " , LOCTEXT ( " ReleaseForceLoadActorsInDataLayers " , " Release Force Load Actor(s) in Data Layer(s) " ) , FText ( ) , FSlateIcon ( ) ,
2024-02-23 08:42:17 -05:00
FUIAction (
FExecuteAction : : CreateLambda ( [ SelectedDataLayers ] ( )
{
check ( ! SelectedDataLayers . IsEmpty ( ) ) ;
2024-06-05 14:17:46 -04:00
const FScopedTransaction Transaction ( LOCTEXT ( " ReleaseForceLoadActorsInDataLayers " , " Release Force Load Actor(s) in Data Layer ( s ) " )) ;
2024-02-23 08:42:17 -05:00
UDataLayerEditorSubsystem : : Get ( ) - > SetActorsPinStateInDataLayers ( SelectedDataLayers , false ) ;
} ) ,
FCanExecuteAction : : CreateLambda ( [ SelectedDataLayers ] { return ! SelectedDataLayers . IsEmpty ( ) ; } )
) ) ;
}
2021-11-07 23:43:01 -05:00
{
FToolMenuSection & Section = InMenu - > AddSection ( " DataLayerExpansion " , LOCTEXT ( " DataLayerExpansion " , " Expansion " ) ) ;
Section . AddMenuEntry ( " CollapseAllDataLayers " , LOCTEXT ( " CollapseAllDataLayers " , " Collapse All Data Layers " ) , FText ( ) , FSlateIcon ( ) ,
FUIAction (
FExecuteAction : : CreateLambda ( [ SceneOutliner , SelectedDataLayers ] ( ) {
2024-01-30 14:18:27 -05:00
check ( ! SelectedDataLayers . IsEmpty ( ) ) ;
{
GEditor - > SelectNone ( /*bNoteSelectionChange*/ false , /*bDeselectBSPSurfs*/ true ) ;
SceneOutliner - > CollapseAll ( ) ;
} } ) ,
2021-11-07 23:43:01 -05:00
FCanExecuteAction : : CreateLambda ( [ SelectedDataLayers ] { return ! SelectedDataLayers . IsEmpty ( ) ; } )
) ) ;
Section . AddMenuEntry ( " ExpandAllDataLayers " , LOCTEXT ( " ExpandAllDataLayers " , " Expand All Data Layers " ) , FText ( ) , FSlateIcon ( ) ,
FUIAction (
FExecuteAction : : CreateLambda ( [ SceneOutliner , SelectedDataLayers ] ( ) {
2024-01-30 14:18:27 -05:00
check ( ! SelectedDataLayers . IsEmpty ( ) ) ;
{
GEditor - > SelectNone ( /*bNoteSelectionChange*/ false , /*bDeselectBSPSurfs*/ true ) ;
SceneOutliner - > ExpandAll ( ) ;
} } ) ,
2021-11-07 23:43:01 -05:00
FCanExecuteAction : : CreateLambda ( [ SelectedDataLayers ] { return ! SelectedDataLayers . IsEmpty ( ) ; } )
2020-12-03 12:41:42 -04:00
) ) ;
2020-10-28 06:51:40 -04:00
}
2022-03-08 09:40:27 -05:00
{
FToolMenuSection & Section = InMenu - > AddSection ( " DataLayerActorEditorContext " , LOCTEXT ( " DataLayerActorEditorContext " , " Actor Editor Context " ) ) ;
Section . AddMenuEntry ( " MakeCurrentDataLayers " , LOCTEXT ( " MakeCurrentDataLayers " , " Make Current Data Layer(s) " ) , FText ( ) , FSlateIcon ( ) ,
FUIAction (
2022-06-17 13:03:41 -04:00
FExecuteAction : : CreateLambda ( [ Mode , SceneOutliner , SelectedDataLayers ] ( )
2022-03-08 09:40:27 -05:00
{
2022-05-16 08:48:27 -04:00
const FScopedTransaction Transaction ( LOCTEXT ( " MakeCurrentDataLayers " , " Make Current Data Layer(s) " )) ;
2023-03-26 15:44:07 -04:00
for ( TWeakObjectPtr < const UDataLayerInstance > & DataLayerInstance : Mode - > SelectedDataLayersSet )
2022-03-08 09:40:27 -05:00
{
2023-03-26 15:44:07 -04:00
if ( DataLayerInstance . IsValid ( ) )
2022-03-08 09:40:27 -05:00
{
2023-03-26 15:44:07 -04:00
UDataLayerEditorSubsystem : : Get ( ) - > AddToActorEditorContext ( const_cast < UDataLayerInstance * > ( DataLayerInstance . Get ( ) ) ) ;
2022-03-08 09:40:27 -05:00
}
}
} ) ,
2023-03-26 15:44:07 -04:00
FCanExecuteAction : : CreateLambda ( [ Mode ]
{
return Algo : : AnyOf ( Mode - > SelectedDataLayersSet , [ ] ( const TWeakObjectPtr < const UDataLayerInstance > & DataLayerInstance )
{
return DataLayerInstance . IsValid ( ) & & DataLayerInstance - > CanBeInActorEditorContext ( ) & & ! DataLayerInstance - > IsInActorEditorContext ( ) ;
} ) ;
} )
2022-03-08 09:40:27 -05:00
) ) ;
Section . AddMenuEntry ( " RemoveCurrentDataLayers " , LOCTEXT ( " RemoveCurrentDataLayers " , " Remove Current Data Layer(s) " ) , FText ( ) , FSlateIcon ( ) ,
FUIAction (
2022-06-17 13:03:41 -04:00
FExecuteAction : : CreateLambda ( [ Mode , SceneOutliner , SelectedDataLayers ] ( )
2022-03-08 09:40:27 -05:00
{
2022-05-16 08:48:27 -04:00
const FScopedTransaction Transaction ( LOCTEXT ( " RemoveCurrentDataLayers " , " Remove Current Data Layer(s) " )) ;
2023-03-26 15:44:07 -04:00
for ( TWeakObjectPtr < const UDataLayerInstance > & DataLayerInstance : Mode - > SelectedDataLayersSet )
2022-03-08 09:40:27 -05:00
{
2023-03-26 15:44:07 -04:00
if ( DataLayerInstance . IsValid ( ) )
2022-03-08 09:40:27 -05:00
{
2023-03-26 15:44:07 -04:00
UDataLayerEditorSubsystem : : Get ( ) - > RemoveFromActorEditorContext ( const_cast < UDataLayerInstance * > ( DataLayerInstance . Get ( ) ) ) ;
2022-03-08 09:40:27 -05:00
}
}
} ) ,
2023-03-26 15:44:07 -04:00
FCanExecuteAction : : CreateLambda ( [ Mode ]
{
return Algo : : AnyOf ( Mode - > SelectedDataLayersSet , [ ] ( const TWeakObjectPtr < const UDataLayerInstance > & DatalLayerInstance )
{
return DatalLayerInstance . IsValid ( ) & & DatalLayerInstance - > CanBeInActorEditorContext ( ) & & DatalLayerInstance - > IsInActorEditorContext ( ) ;
} ) ;
} )
2022-03-08 09:40:27 -05:00
) ) ;
2024-01-30 14:18:27 -05:00
Section . AddMenuEntry ( " ClearCurrentDataLayers " , LOCTEXT ( " ClearCurrentDataLayers " , " Clear Current Data Layer(s) " ) , FText ( ) , FSlateIcon ( ) ,
2022-03-08 09:40:27 -05:00
FUIAction (
2022-06-17 13:03:41 -04:00
FExecuteAction : : CreateLambda ( [ AllDataLayers ] ( )
2022-03-08 09:40:27 -05:00
{
check ( ! AllDataLayers . IsEmpty ( ) ) ;
{
2024-02-01 10:46:16 -05:00
const FScopedTransaction Transaction ( LOCTEXT ( " ClearCurrentDataLayers " , " Clear Current Data Layer(s) " )) ;
2022-03-15 13:52:28 -04:00
for ( const UDataLayerInstance * DataLayer : AllDataLayers )
2022-03-08 09:40:27 -05:00
{
2022-06-17 13:03:41 -04:00
UDataLayerEditorSubsystem : : Get ( ) - > RemoveFromActorEditorContext ( const_cast < UDataLayerInstance * > ( DataLayer ) ) ;
2022-03-08 09:40:27 -05:00
}
2024-01-30 14:18:27 -05:00
}
} ) ,
2022-03-08 09:40:27 -05:00
FCanExecuteAction : : CreateLambda ( [ bHasActorEditorContextDataLayers ] { return bHasActorEditorContextDataLayers ; } )
) ) ;
}
2020-10-28 06:51:40 -04:00
{
FToolMenuSection & Section = InMenu - > AddSection ( " DataLayerVisibility " , LOCTEXT ( " DataLayerVisibility " , " Visibility " ) ) ;
2021-03-17 15:17:35 -04:00
Section . AddMenuEntry ( " MakeAllDataLayersVisible " , LOCTEXT ( " MakeAllDataLayersVisible " , " Make All Data Layers Visible " ) , FText ( ) , FSlateIcon ( ) ,
2020-10-28 06:51:40 -04:00
FUIAction (
2024-01-30 14:18:27 -05:00
FExecuteAction : : CreateLambda ( [ AllDataLayers ] ( )
{
2020-10-28 06:51:40 -04:00
check ( ! AllDataLayers . IsEmpty ( ) ) ;
{
2022-05-16 08:48:27 -04:00
const FScopedTransaction Transaction ( LOCTEXT ( " MakeAllDataLayersVisible " , " Make All Data Layers Visible " ) ) ;
2022-06-17 13:03:41 -04:00
UDataLayerEditorSubsystem : : Get ( ) - > MakeAllDataLayersVisible ( ) ;
2024-01-30 14:18:27 -05:00
}
} ) ,
2021-11-07 23:43:01 -05:00
FCanExecuteAction : : CreateLambda ( [ AllDataLayers ] { return ! AllDataLayers . IsEmpty ( ) ; } )
2020-12-03 12:41:42 -04:00
) ) ;
2020-10-28 06:51:40 -04:00
}
2022-11-21 17:19:31 -05:00
if ( ! UDataLayerEditorSubsystem : : Get ( ) - > HasDeprecatedDataLayers ( ) )
{
FToolMenuSection & Section = InMenu - > AddSection ( " AssetOptionsSection " , LOCTEXT ( " AssetOptionsText " , " Asset Options " ) ) ;
2023-02-16 15:59:16 -05:00
Section . AddMenuEntryWithCommandList ( FGlobalEditorCommonCommands : : Get ( ) . FindInContentBrowser , Mode - > Commands ) ;
2024-02-23 09:32:35 -05:00
const UExternalDataLayerInstance * ExternalDataLayerInstance = SelectedDataLayers . Num ( ) = = 1 ? Cast < UExternalDataLayerInstance > ( SelectedDataLayers [ 0 ] ) : nullptr ;
if ( const UExternalDataLayerAsset * ExternalDataLayerAsset = ExternalDataLayerInstance ? ExternalDataLayerInstance - > GetExternalDataLayerAsset ( ) : nullptr )
{
Section . AddMenuEntry ( " BrowseToPluginAsset " , LOCTEXT ( " BrowseToPluginAsset " , " Browse to Plugin Asset " ) , FText ( ) , FSlateIcon ( FAppStyle : : GetAppStyleSetName ( ) , " SystemWideCommands.FindInContentBrowser " ) ,
FUIAction (
FExecuteAction : : CreateLambda ( [ ExternalDataLayerAsset ] ( )
{
UExternalDataLayerEngineSubsystem & ExternalDataLayerEngineSubsystem = UExternalDataLayerEngineSubsystem : : Get ( ) ;
TArray < UObject * > Objects ; ;
for ( UObject * Client : ExternalDataLayerEngineSubsystem . GetClientsForExternalDataLayerAsset ( ExternalDataLayerAsset ) )
{
if ( UDataAsset * DataAsset = Client - > GetTypedOuter < UDataAsset > ( ) )
{
Objects . Add ( DataAsset ) ;
}
}
if ( ! Objects . IsEmpty ( ) )
{
GEditor - > SyncBrowserToObjects ( Objects ) ;
}
} )
) ) ;
}
2022-11-21 17:19:31 -05:00
}
2020-10-28 06:51:40 -04:00
} ) ) ;
}
if ( ! ToolMenus - > IsMenuRegistered ( DefaultContextMenuName ) )
{
ToolMenus - > RegisterMenu ( DefaultContextMenuName , DefaultContextBaseMenuName ) ;
}
}
TSharedPtr < SWidget > FDataLayerMode : : CreateContextMenu ( )
{
RegisterContextMenu ( ) ;
FSceneOutlinerItemSelection ItemSelection ( SceneOutliner - > GetSelection ( ) ) ;
2023-02-02 18:41:35 -05:00
CacheSelectedItems ( ItemSelection ) ;
2020-10-28 06:51:40 -04:00
USceneOutlinerMenuContext * ContextObject = NewObject < USceneOutlinerMenuContext > ( ) ;
ContextObject - > SceneOutliner = StaticCastSharedRef < SSceneOutliner > ( SceneOutliner - > AsShared ( ) ) ;
ContextObject - > bShowParentTree = SceneOutliner - > GetSharedData ( ) . bShowParentTree ;
ContextObject - > NumSelectedItems = ItemSelection . Num ( ) ;
FToolMenuContext Context ( ContextObject ) ;
FName MenuName = DefaultContextMenuName ;
SceneOutliner - > GetSharedData ( ) . ModifyContextMenu . ExecuteIfBound ( MenuName , Context ) ;
2023-02-02 18:41:35 -05:00
// Add Extenders
FDataLayerEditorModule & DataLayerEditorModule = FModuleManager : : LoadModuleChecked < FDataLayerEditorModule > ( " DataLayerEditor " ) ;
TArray < FDataLayerEditorModule : : FDataLayersMenuExtender > & MenuExtenderDelegates = DataLayerEditorModule . GetAllDataLayersMenuExtenders ( ) ;
TArray < TSharedPtr < FExtender > > Extenders ;
if ( ! MenuExtenderDelegates . IsEmpty ( ) )
{
for ( const FDataLayerEditorModule : : FDataLayersMenuExtender & MenuExtender : MenuExtenderDelegates )
{
if ( MenuExtender . IsBound ( ) )
{
Extenders . Add ( MenuExtender . Execute ( Commands . ToSharedRef ( ) , SelectedDataLayersSet , SelectedDataLayerActors ) ) ;
}
}
if ( ! Extenders . IsEmpty ( ) )
{
Context . AddExtender ( FExtender : : Combine ( Extenders ) ) ;
}
}
2020-10-28 06:51:40 -04:00
// Build up the menu for a selection
UToolMenus * ToolMenus = UToolMenus : : Get ( ) ;
UToolMenu * Menu = ToolMenus - > GenerateMenu ( MenuName , Context ) ;
for ( const FToolMenuSection & Section : Menu - > Sections )
{
if ( Section . Blocks . Num ( ) > 0 )
{
return ToolMenus - > GenerateWidget ( Menu ) ;
}
}
return nullptr ;
}
2023-09-01 13:03:00 -04:00
void FDataLayerMode : : InitializeViewMenuExtender ( TSharedPtr < FExtender > Extender )
2021-11-07 23:43:01 -05:00
{
2023-09-01 13:03:00 -04:00
Extender - > AddMenuExtension ( SceneOutliner : : ExtensionHooks : : Show , EExtensionHook : : First , nullptr , FMenuExtensionDelegate : : CreateLambda ( [ this ] ( FMenuBuilder & MenuBuilder )
{
MenuBuilder . AddMenuEntry (
LOCTEXT ( " ToggleHideLevelInstanceContent " , " Hide Level Instance Content " ) ,
LOCTEXT ( " ToggleHideLevelInstanceContentToolTip " , " When enabled, hides all level instance content. " ) ,
FSlateIcon ( ) ,
FUIAction ( FExecuteAction : : CreateLambda ( [ this ] ( )
{
UWorldPartitionEditorPerProjectUserSettings * Settings = GetMutableDefault < UWorldPartitionEditorPerProjectUserSettings > ( ) ;
bHideLevelInstanceContent = ! bHideLevelInstanceContent ;
Settings - > bHideLevelInstanceContent = bHideLevelInstanceContent ;
Settings - > PostEditChange ( ) ;
if ( auto DataLayerHierarchy = StaticCast < FDataLayerHierarchy * > ( Hierarchy . Get ( ) ) )
{
DataLayerHierarchy - > SetShowLevelInstanceContent ( ! bHideLevelInstanceContent ) ;
}
SceneOutliner - > FullRefresh ( ) ;
} ) ,
FCanExecuteAction ( ) ,
FIsActionChecked : : CreateLambda ( [ this ] ( ) { return bHideLevelInstanceContent ; } ) ) ,
NAME_None ,
EUserInterfaceActionType : : ToggleButton
) ;
} ) ) ;
Extender - > AddMenuExtension ( SceneOutliner : : ExtensionHooks : : Show , EExtensionHook : : After , nullptr , FMenuExtensionDelegate : : CreateLambda ( [ this ] ( FMenuBuilder & MenuBuilder )
{
MenuBuilder . AddMenuEntry (
LOCTEXT ( " ToggleHighlightSelectedDataLayers " , " Highlight Selected " ) ,
LOCTEXT ( " ToggleHighlightSelectedDataLayersToolTip " , " When enabled, highlights Data Layers containing actors that are currently selected. " ) ,
FSlateIcon ( ) ,
FUIAction ( FExecuteAction : : CreateLambda ( [ this ] ( )
2021-11-25 13:51:47 -05:00
{
UWorldPartitionEditorPerProjectUserSettings * Settings = GetMutableDefault < UWorldPartitionEditorPerProjectUserSettings > ( ) ;
bHighlightSelectedDataLayers = ! bHighlightSelectedDataLayers ;
Settings - > bHighlightSelectedDataLayers = bHighlightSelectedDataLayers ;
Settings - > PostEditChange ( ) ;
if ( auto DataLayerHierarchy = StaticCast < FDataLayerHierarchy * > ( Hierarchy . Get ( ) ) )
{
DataLayerHierarchy - > SetHighlightSelectedDataLayers ( bHighlightSelectedDataLayers ) ;
}
SceneOutliner - > FullRefresh ( ) ;
2023-09-01 13:03:00 -04:00
} ) ,
2021-11-25 13:51:47 -05:00
FCanExecuteAction ( ) ,
2023-09-01 13:03:00 -04:00
FIsActionChecked : : CreateLambda ( [ this ] ( ) { return bHighlightSelectedDataLayers ; } ) ) ,
NAME_None ,
EUserInterfaceActionType : : ToggleButton
) ;
2021-11-25 13:51:47 -05:00
2023-09-01 13:03:00 -04:00
MenuBuilder . BeginSection ( " Advanced " , LOCTEXT ( " ShowAdvancedHeading " , " Advanced " ) ) ;
MenuBuilder . AddMenuEntry (
LOCTEXT ( " ToggleAllowRuntimeDataLayerEditing " , " Allow Runtime Data Layer Editing " ) ,
LOCTEXT ( " ToggleAllowRuntimeDataLayerEditingToolTip " , " When enabled, allows editing of Runtime Data Layers. " ) ,
FSlateIcon ( ) ,
FUIAction ( FExecuteAction : : CreateLambda ( [ this ] ( )
2021-11-18 14:37:34 -05:00
{
2021-11-26 14:01:04 -05:00
if ( AWorldDataLayers * WorldDataLayers = RepresentingWorld . IsValid ( ) ? RepresentingWorld - > GetWorldDataLayers ( ) : nullptr )
{
2022-05-16 08:48:27 -04:00
const FScopedTransaction Transaction ( LOCTEXT ( " ToggleAllowRuntimeDataLayerEditingTransaction " , " Toggle Allow Runtime Data Layer Editing " ) ) ;
2021-11-26 14:01:04 -05:00
WorldDataLayers - > SetAllowRuntimeDataLayerEditing ( ! WorldDataLayers - > GetAllowRuntimeDataLayerEditing ( ) ) ;
}
2021-11-18 14:37:34 -05:00
SceneOutliner - > FullRefresh ( ) ;
} ) ,
2021-11-07 23:43:01 -05:00
FCanExecuteAction ( ) ,
2021-11-26 14:01:04 -05:00
FIsActionChecked : : CreateLambda ( [ this ] ( )
{
const AWorldDataLayers * WorldDataLayers = RepresentingWorld . IsValid ( ) ? RepresentingWorld - > GetWorldDataLayers ( ) : nullptr ;
return WorldDataLayers ? WorldDataLayers - > GetAllowRuntimeDataLayerEditing ( ) : true ;
2023-09-01 13:03:00 -04:00
} ) ) ,
NAME_None ,
EUserInterfaceActionType : : ToggleButton
) ;
2021-11-18 14:37:34 -05:00
2023-09-01 13:03:00 -04:00
TArray < UDataLayerInstance * > AllDataLayers ;
if ( const UDataLayerManager * DataLayerManager = UDataLayerManager : : GetDataLayerManager ( GetOwningWorld ( ) ) )
2021-11-18 14:37:34 -05:00
{
2023-09-01 13:03:00 -04:00
DataLayerManager - > ForEachDataLayerInstance ( [ & AllDataLayers ] ( UDataLayerInstance * DataLayer )
{
AllDataLayers . Add ( DataLayer ) ;
return true ;
} ) ;
}
2021-11-18 14:37:34 -05:00
2023-09-01 13:03:00 -04:00
MenuBuilder . AddMenuEntry (
LOCTEXT ( " ResetDataLayerUserSettings " , " Reset User Settings " ) ,
LOCTEXT ( " ResetDataLayerUserSettingsToolTip " , " Resets Data Layers User Settings to their initial values. " ) ,
FSlateIcon ( ) ,
FUIAction ( FExecuteAction : : CreateLambda ( [ this ] ( )
2021-11-18 14:37:34 -05:00
{
2022-05-16 08:48:27 -04:00
const FScopedTransaction Transaction ( LOCTEXT ( " ResetDataLayerUserSettings " , " Reset User Settings " ) ) ;
2021-11-18 14:37:34 -05:00
DataLayerEditorSubsystem - > ResetUserSettings ( ) ;
2023-09-01 13:03:00 -04:00
} ) )
) ;
2021-11-18 14:37:34 -05:00
2023-09-01 13:03:00 -04:00
MenuBuilder . EndSection ( ) ;
2021-11-07 23:43:01 -05:00
2023-09-01 13:03:00 -04:00
MenuBuilder . BeginSection ( " World " , LOCTEXT ( " ShowWorldHeading " , " World " ) ) ;
MenuBuilder . AddSubMenu (
LOCTEXT ( " ChooseWorldSubMenu " , " Choose World " ) ,
LOCTEXT ( " ChooseWorldSubMenuToolTip " , " Choose the world to display in the outliner. " ) ,
FNewMenuDelegate : : CreateRaw ( this , & FDataLayerMode : : BuildWorldPickerMenu )
) ;
MenuBuilder . EndSection ( ) ;
} ) ) ;
2021-11-07 23:43:01 -05:00
}
void FDataLayerMode : : BuildWorldPickerMenu ( FMenuBuilder & MenuBuilder )
{
MenuBuilder . BeginSection ( " Worlds " , LOCTEXT ( " WorldsHeading " , " Worlds " ) ) ;
{
MenuBuilder . AddMenuEntry (
LOCTEXT ( " AutoWorld " , " Auto " ) ,
LOCTEXT ( " AutoWorldToolTip " , " Automatically pick the world to display based on context. " ) ,
FSlateIcon ( ) ,
FUIAction (
FExecuteAction : : CreateRaw ( this , & FDataLayerMode : : OnSelectWorld , TWeakObjectPtr < UWorld > ( ) ) ,
FCanExecuteAction ( ) ,
FIsActionChecked : : CreateRaw ( this , & FDataLayerMode : : IsWorldChecked , TWeakObjectPtr < UWorld > ( ) )
) ,
NAME_None ,
EUserInterfaceActionType : : RadioButton
) ;
for ( const FWorldContext & Context : GEngine - > GetWorldContexts ( ) )
{
UWorld * World = Context . World ( ) ;
if ( World & & ( World - > WorldType = = EWorldType : : PIE | | Context . WorldType = = EWorldType : : Editor ) )
{
MenuBuilder . AddMenuEntry (
SceneOutliner : : GetWorldDescription ( World ) ,
LOCTEXT ( " ChooseWorldToolTip " , " Display actors for this world. " ) ,
FSlateIcon ( ) ,
FUIAction (
FExecuteAction : : CreateRaw ( this , & FDataLayerMode : : OnSelectWorld , MakeWeakObjectPtr ( World ) ) ,
FCanExecuteAction ( ) ,
FIsActionChecked : : CreateRaw ( this , & FDataLayerMode : : IsWorldChecked , MakeWeakObjectPtr ( World ) )
) ,
NAME_None ,
EUserInterfaceActionType : : RadioButton
) ;
}
}
}
MenuBuilder . EndSection ( ) ;
}
void FDataLayerMode : : OnSelectWorld ( TWeakObjectPtr < UWorld > World )
{
UserChosenWorld = World ;
SceneOutliner - > FullRefresh ( ) ;
}
bool FDataLayerMode : : IsWorldChecked ( TWeakObjectPtr < UWorld > World ) const
{
return ( UserChosenWorld = = World ) | | ( World . IsExplicitlyNull ( ) & & ! UserChosenWorld . IsValid ( ) ) ;
}
2020-10-28 06:51:40 -04:00
TUniquePtr < ISceneOutlinerHierarchy > FDataLayerMode : : CreateHierarchy ( )
{
2021-11-07 23:43:01 -05:00
TUniquePtr < FDataLayerHierarchy > DataLayerHierarchy = FDataLayerHierarchy : : Create ( this , RepresentingWorld ) ;
2021-11-25 13:51:47 -05:00
DataLayerHierarchy - > SetShowEditorDataLayers ( ! bHideEditorDataLayers ) ;
DataLayerHierarchy - > SetShowRuntimeDataLayers ( ! bHideRuntimeDataLayers ) ;
DataLayerHierarchy - > SetShowDataLayerActors ( ! bHideDataLayerActors ) ;
DataLayerHierarchy - > SetShowUnloadedActors ( ! bHideUnloadedActors ) ;
DataLayerHierarchy - > SetShowOnlySelectedActors ( bShowOnlySelectedActors ) ;
DataLayerHierarchy - > SetHighlightSelectedDataLayers ( bHighlightSelectedDataLayers ) ;
2022-05-10 10:22:54 -04:00
DataLayerHierarchy - > SetShowLevelInstanceContent ( ! bHideLevelInstanceContent ) ;
2021-11-07 23:43:01 -05:00
return DataLayerHierarchy ;
2020-10-28 06:51:40 -04:00
}
2023-02-02 18:41:35 -05:00
void FDataLayerMode : : CacheSelectedItems ( const FSceneOutlinerItemSelection & Selection )
2020-11-03 17:16:48 -04:00
{
2020-11-03 18:28:22 -04:00
SelectedDataLayersSet . Empty ( ) ;
2020-11-03 17:16:48 -04:00
SelectedDataLayerActors . Empty ( ) ;
2020-11-03 18:28:22 -04:00
Selection . ForEachItem < FDataLayerTreeItem > ( [ this ] ( const FDataLayerTreeItem & Item ) { SelectedDataLayersSet . Add ( Item . GetDataLayer ( ) ) ; } ) ;
2020-11-03 17:16:48 -04:00
Selection . ForEachItem < FDataLayerActorTreeItem > ( [ this ] ( const FDataLayerActorTreeItem & Item ) { SelectedDataLayerActors . Add ( FSelectedDataLayerActor ( Item . GetDataLayer ( ) , Item . GetActor ( ) ) ) ; } ) ;
2023-02-02 18:41:35 -05:00
}
void FDataLayerMode : : OnItemSelectionChanged ( FSceneOutlinerTreeItemPtr TreeItem , ESelectInfo : : Type SelectionType , const FSceneOutlinerItemSelection & Selection )
{
CacheSelectedItems ( Selection ) ;
2021-01-27 13:03:11 -04:00
if ( DataLayerBrowser )
{
DataLayerBrowser - > OnSelectionChanged ( SelectedDataLayersSet ) ;
}
2021-11-07 23:43:01 -05:00
if ( OnItemPicked . IsBound ( ) )
{
auto SelectedItems = SceneOutliner - > GetSelectedItems ( ) ;
if ( SelectedItems . Num ( ) > 0 )
{
auto FirstItem = SelectedItems [ 0 ] ;
if ( FirstItem - > CanInteract ( ) )
{
OnItemPicked . ExecuteIfBound ( FirstItem . ToSharedRef ( ) ) ;
}
}
}
2020-11-03 17:16:48 -04:00
}
2020-10-28 06:51:40 -04:00
void FDataLayerMode : : Rebuild ( )
{
2021-11-07 23:43:01 -05:00
FilteredDataLayerCount = 0 ;
ApplicableDataLayers . Empty ( ) ;
2020-10-28 06:51:40 -04:00
ChooseRepresentingWorld ( ) ;
Hierarchy = CreateHierarchy ( ) ;
2021-11-07 23:43:01 -05:00
// Hide delete actor column when it's not necessary
const bool bShowDeleteButtonColumn = ! bHideDataLayerActors & & RepresentingWorld . IsValid ( ) & & ! RepresentingWorld - > IsPlayInEditor ( ) ;
SceneOutliner - > SetColumnVisibility ( FDataLayerOutlinerDeleteButtonColumn : : GetID ( ) , bShowDeleteButtonColumn ) ;
if ( DataLayerBrowser )
{
DataLayerBrowser - > OnSelectionChanged ( SelectedDataLayersSet ) ;
}
2020-10-28 06:51:40 -04:00
}
void FDataLayerMode : : ChooseRepresentingWorld ( )
{
// Select a world to represent
RepresentingWorld = nullptr ;
// If a specified world was provided, represent it
if ( SpecifiedWorldToDisplay . IsValid ( ) )
{
RepresentingWorld = SpecifiedWorldToDisplay . Get ( ) ;
}
// check if the user-chosen world is valid and in the editor contexts
if ( ! RepresentingWorld . IsValid ( ) & & UserChosenWorld . IsValid ( ) )
{
for ( const FWorldContext & Context : GEngine - > GetWorldContexts ( ) )
{
if ( UserChosenWorld . Get ( ) = = Context . World ( ) )
{
RepresentingWorld = UserChosenWorld . Get ( ) ;
break ;
}
}
}
// If the user did not manually select a world, try to pick the most suitable world context
if ( ! RepresentingWorld . IsValid ( ) )
{
// ideally we want a PIE world that is standalone or the first client
for ( const FWorldContext & Context : GEngine - > GetWorldContexts ( ) )
{
UWorld * World = Context . World ( ) ;
if ( World & & Context . WorldType = = EWorldType : : PIE )
{
if ( World - > GetNetMode ( ) = = NM_Standalone )
{
RepresentingWorld = World ;
break ;
}
else if ( World - > GetNetMode ( ) = = NM_Client & & Context . PIEInstance = = 2 ) / / Slightly dangerous : assumes server is always PIEInstance = 1 ;
{
RepresentingWorld = World ;
break ;
}
}
}
}
if ( RepresentingWorld = = nullptr )
{
// still not world so fallback to old logic where we just prefer PIE over Editor
for ( const FWorldContext & Context : GEngine - > GetWorldContexts ( ) )
{
if ( Context . WorldType = = EWorldType : : PIE )
{
RepresentingWorld = Context . World ( ) ;
break ;
}
else if ( Context . WorldType = = EWorldType : : Editor )
{
RepresentingWorld = Context . World ( ) ;
}
}
}
}
2022-03-15 13:52:28 -04:00
bool FDataLayerMode : : ShouldExpandDataLayer ( const UDataLayerInstance * DataLayer ) const
2021-11-25 13:51:47 -05:00
{
if ( bHighlightSelectedDataLayers | | bShowOnlySelectedActors )
{
if ( DataLayer )
{
if ( ( bShowOnlySelectedActors & & DataLayerEditorSubsystem - > DoesDataLayerContainSelectedActors ( DataLayer ) ) | |
( ContainsSelectedChildDataLayer ( DataLayer ) & & ! DataLayer - > GetChildren ( ) . IsEmpty ( ) ) )
{
return true ;
}
}
}
return false ;
}
2022-03-15 13:52:28 -04:00
bool FDataLayerMode : : ContainsSelectedChildDataLayer ( const UDataLayerInstance * DataLayer ) const
2021-11-25 13:51:47 -05:00
{
if ( DataLayer )
{
bool bFoundSelected = false ;
2022-03-15 13:52:28 -04:00
DataLayer - > ForEachChild ( [ this , & bFoundSelected ] ( const UDataLayerInstance * Child )
2021-11-25 13:51:47 -05:00
{
if ( DataLayerEditorSubsystem - > DoesDataLayerContainSelectedActors ( Child ) | | ContainsSelectedChildDataLayer ( Child ) )
{
bFoundSelected = true ;
return false ;
}
return true ;
} ) ;
return bFoundSelected ;
}
return false ;
} ;
TSharedRef < FSceneOutlinerFilter > FDataLayerMode : : CreateShowOnlySelectedActorsFilter ( )
{
2022-03-15 13:52:28 -04:00
auto IsActorSelected = [ ] ( const AActor * InActor , const UDataLayerInstance * InDataLayer )
2021-11-25 13:51:47 -05:00
{
return InActor & & InActor - > IsSelected ( ) ;
} ;
return MakeShareable ( new FDataLayerActorFilter ( FDataLayerActorTreeItem : : FFilterPredicate : : CreateStatic ( IsActorSelected ) , FSceneOutlinerFilter : : EDefaultBehaviour : : Pass , FDataLayerActorTreeItem : : FFilterPredicate : : CreateStatic ( IsActorSelected ) ) ) ;
}
void FDataLayerMode : : SynchronizeSelection ( )
{
if ( ! bShowOnlySelectedActors & & ! bHighlightSelectedDataLayers )
{
return ;
}
TArray < AActor * > Actors ;
2022-03-15 13:52:28 -04:00
TSet < const UDataLayerInstance * > ActorDataLayersIncludingParents ;
2021-11-25 13:51:47 -05:00
GEditor - > GetSelectedActors ( ) - > GetSelectedObjects < AActor > ( Actors ) ;
for ( const AActor * Actor : Actors )
{
2022-03-15 13:52:28 -04:00
TArray < const UDataLayerInstance * > ActorDataLayers = Actor - > GetDataLayerInstances ( ) ;
for ( const UDataLayerInstance * DataLayer : ActorDataLayers )
2021-11-25 13:51:47 -05:00
{
2022-03-15 13:52:28 -04:00
const UDataLayerInstance * CurrentDataLayer = DataLayer ;
2021-11-25 13:51:47 -05:00
while ( CurrentDataLayer )
{
bool bIsAlreadyInSet = false ;
ActorDataLayersIncludingParents . Add ( CurrentDataLayer , & bIsAlreadyInSet ) ;
if ( ! bIsAlreadyInSet )
{
FSceneOutlinerTreeItemPtr TreeItem = SceneOutliner - > GetTreeItem ( CurrentDataLayer , false ) ;
if ( TreeItem & & ShouldExpandDataLayer ( CurrentDataLayer ) )
{
SceneOutliner - > SetItemExpansion ( TreeItem , true ) ;
}
}
CurrentDataLayer = CurrentDataLayer - > GetParent ( ) ;
}
}
}
}
2024-04-15 09:16:36 -04:00
void FDataLayerMode : : OnPostLoadMapWithWorld ( UWorld * World )
{
SceneOutliner - > FullRefresh ( ) ;
}
2021-11-25 13:51:47 -05:00
void FDataLayerMode : : OnLevelSelectionChanged ( UObject * Obj )
{
if ( ! bShowOnlySelectedActors & & ! bHighlightSelectedDataLayers )
{
return ;
}
RefreshSelection ( ) ;
}
void FDataLayerMode : : RefreshSelection ( )
{
SceneOutliner - > FullRefresh ( ) ;
SceneOutliner - > RefreshSelection ( ) ;
}
2021-11-07 23:43:01 -05:00
//
// FDataLayerPickingMode : Lightweight version of FDataLayerMode used to show the DataLayer hierarchy and choose one.
//
FDataLayerPickingMode : : FDataLayerPickingMode ( const FDataLayerModeParams & Params )
: FDataLayerMode ( Params )
{
bHideDataLayerActors = true ;
Rebuild ( ) ;
SceneOutliner - > ExpandAll ( ) ;
}
2024-01-30 14:18:27 -05:00
TSharedRef < SWidget > FDataLayerPickingMode : : CreateDataLayerPickerWidget ( FOnDataLayerInstancePicked OnDataLayerInstancePicked , FOnShouldFilterDataLayerInstance OnShouldFilterDataLayerInstance )
2021-11-07 23:43:01 -05:00
{
// Create mini DataLayers outliner to pick a DataLayer
FSceneOutlinerInitializationOptions InitOptions ;
InitOptions . bShowHeaderRow = false ;
InitOptions . bShowParentTree = true ;
InitOptions . bShowCreateNewFolder = false ;
InitOptions . bFocusSearchBoxWhenOpened = true ;
2024-01-30 14:18:27 -05:00
if ( OnShouldFilterDataLayerInstance . IsBound ( ) )
{
2024-03-11 11:38:41 -04:00
InitOptions . Filters - > AddFilterPredicate < FDataLayerTreeItem > ( FDataLayerTreeItem : : FFilterPredicate : : CreateLambda ( [ OnShouldFilterDataLayerInstance ] ( const UDataLayerInstance * DataLayerInstance ) { return ! OnShouldFilterDataLayerInstance . Execute ( DataLayerInstance ) ; } ) , FSceneOutlinerFilter : : EDefaultBehaviour : : Pass ) ;
2024-01-30 14:18:27 -05:00
}
2021-11-07 23:43:01 -05:00
InitOptions . ColumnMap . Add ( FSceneOutlinerBuiltInColumnTypes : : Label ( ) , FSceneOutlinerColumnInfo ( ESceneOutlinerColumnVisibility : : Visible , 2 ) ) ;
2024-01-30 14:18:27 -05:00
InitOptions . ModeFactory = FCreateSceneOutlinerMode : : CreateLambda ( [ OnDataLayerInstancePicked ] ( SSceneOutliner * Outliner )
2021-11-07 23:43:01 -05:00
{
2024-01-30 14:18:27 -05:00
return new FDataLayerPickingMode ( FDataLayerModeParams ( Outliner , nullptr , nullptr , FOnSceneOutlinerItemPicked : : CreateLambda ( [ OnDataLayerInstancePicked ] ( const FSceneOutlinerTreeItemRef & NewParent )
2021-11-07 23:43:01 -05:00
{
FDataLayerTreeItem * DataLayerItem = NewParent - > CastTo < FDataLayerTreeItem > ( ) ;
2022-03-15 13:52:28 -04:00
if ( UDataLayerInstance * DataLayer = DataLayerItem ? DataLayerItem - > GetDataLayer ( ) : nullptr )
2021-11-07 23:43:01 -05:00
{
2024-01-30 14:18:27 -05:00
OnDataLayerInstancePicked . ExecuteIfBound ( DataLayer ) ;
2021-11-07 23:43:01 -05:00
}
FSlateApplication : : Get ( ) . DismissAllMenus ( ) ;
} ) ) ) ;
} ) ;
TSharedRef < SDataLayerOutliner > Outliner = SNew ( SDataLayerOutliner , InitOptions ) . IsEnabled ( FSlateApplication : : Get ( ) . GetNormalExecutionAttribute ( ) ) ;
TSharedRef < SWidget > DataLayerPickerWidget =
SNew ( SVerticalBox )
+ SVerticalBox : : Slot ( )
. MaxHeight ( 400.0f )
[
Outliner
] ;
Outliner - > ExpandAll ( ) ;
return DataLayerPickerWidget ;
}
void FDataLayerPickingMode : : OnItemSelectionChanged ( FSceneOutlinerTreeItemPtr TreeItem , ESelectInfo : : Type SelectionType , const FSceneOutlinerItemSelection & Selection )
{
if ( OnItemPicked . IsBound ( ) )
{
auto SelectedItems = SceneOutliner - > GetSelectedItems ( ) ;
if ( SelectedItems . Num ( ) > 0 )
{
auto FirstItem = SelectedItems [ 0 ] ;
if ( FirstItem - > CanInteract ( ) )
{
if ( const FDataLayerTreeItem * DataLayerItem = FirstItem - > CastTo < FDataLayerTreeItem > ( ) )
{
2024-01-30 14:18:27 -05:00
UDataLayerInstance * DataLayerInstance = DataLayerItem - > GetDataLayer ( ) ;
if ( DataLayerInstance & & ! DataLayerInstance - > IsReadOnly ( ) )
2021-11-07 23:43:01 -05:00
{
OnItemPicked . ExecuteIfBound ( FirstItem . ToSharedRef ( ) ) ;
}
}
}
}
}
}
2021-11-25 13:51:47 -05:00
# undef LOCTEXT_NAMESPACE