// Copyright Epic Games, Inc. All Rights Reserved. #include "LevelInstanceEditorMode.h" #include "LevelInstanceEditorModeToolkit.h" #include "LevelInstanceEditorModeCommands.h" #include "Editor.h" #include "Selection.h" #include "EditorModes.h" #include "Engine/World.h" #include "LevelInstance/LevelInstanceSubsystem.h" #include "LevelInstance/LevelInstanceInterface.h" #include "LevelInstance/ILevelInstanceEditorModule.h" #include "LevelEditorViewport.h" #include "LevelEditorActions.h" #include "EditorModeManager.h" #include "Framework/Application/SlateApplication.h" #include "Modules/ModuleManager.h" #define LOCTEXT_NAMESPACE "LevelInstanceEditorMode" FEditorModeID ULevelInstanceEditorMode::EM_LevelInstanceEditorModeId("EditMode.LevelInstance"); ULevelInstanceEditorMode::ULevelInstanceEditorMode() : UEdMode() { Info = FEditorModeInfo(ULevelInstanceEditorMode::EM_LevelInstanceEditorModeId, LOCTEXT("LevelInstanceEditorModeName", "LevelInstanceEditorMode"), FSlateIcon(), false); bContextRestriction = true; } ULevelInstanceEditorMode::~ULevelInstanceEditorMode() { } void ULevelInstanceEditorMode::OnPreBeginPIE(bool bSimulate) { ExitModeCommand(); } void ULevelInstanceEditorMode::UpdateEngineShowFlags() { for (FLevelEditorViewportClient* LevelVC : GEditor->GetLevelViewportClients()) { if (LevelVC && LevelVC->GetWorld()) { if(ULevelInstanceSubsystem* LevelInstanceSubsystem = LevelVC->GetWorld()->GetSubsystem()) { const bool bEditingLevelInstance = IsContextRestrictedForWorld(LevelVC->GetWorld()); // Make sure we update both Game/Editor showflags LevelVC->EngineShowFlags.EditingLevelInstance = bEditingLevelInstance; LevelVC->LastEngineShowFlags.EditingLevelInstance = bEditingLevelInstance; } } } } void ULevelInstanceEditorMode::Enter() { UEdMode::Enter(); UpdateEngineShowFlags(); FEditorDelegates::PreBeginPIE.AddUObject(this, &ULevelInstanceEditorMode::OnPreBeginPIE); } void ULevelInstanceEditorMode::Exit() { UEdMode::Exit(); UpdateEngineShowFlags(); bContextRestriction = true; FEditorDelegates::PreBeginPIE.RemoveAll(this); } void ULevelInstanceEditorMode::CreateToolkit() { Toolkit = MakeShared(); } void ULevelInstanceEditorMode::ModeTick(float DeltaTime) { Super::ModeTick(DeltaTime); UpdateEngineShowFlags(); } bool ULevelInstanceEditorMode::IsCompatibleWith(FEditorModeID OtherModeID) const { return (OtherModeID != FBuiltinEditorModes::EM_Foliage) && (OtherModeID != FBuiltinEditorModes::EM_Landscape); } void ULevelInstanceEditorMode::BindCommands() { UEdMode::BindCommands(); const TSharedRef& CommandList = Toolkit->GetToolkitCommands(); const FLevelInstanceEditorModeCommands& Commands = FLevelInstanceEditorModeCommands::Get(); CommandList->MapAction( Commands.ExitMode, FExecuteAction::CreateUObject(this, &ULevelInstanceEditorMode::ExitModeCommand), FCanExecuteAction::CreateLambda([&] { // If some actors are selected make sure we don't interfere with the SelectNone command if(GEditor->GetSelectedActors()->Num() > 0) { const FInputChord& SelectNonePrimary = FLevelEditorCommands::Get().SelectNone->GetActiveChord(EMultipleKeyBindingIndex::Primary).Get(); if (SelectNonePrimary.IsValidChord() && Commands.ExitMode->HasActiveChord(SelectNonePrimary)) { return false; } const FInputChord& SelectNoneSecondary = FLevelEditorCommands::Get().SelectNone->GetActiveChord(EMultipleKeyBindingIndex::Secondary).Get(); if (SelectNoneSecondary.IsValidChord() && Commands.ExitMode->HasActiveChord(SelectNoneSecondary)) { return false; } } return true; })); CommandList->MapAction( Commands.ToggleContextRestriction, FExecuteAction::CreateUObject(this, &ULevelInstanceEditorMode::ToggleContextRestrictionCommand), FCanExecuteAction(), FIsActionChecked::CreateUObject(this, &ULevelInstanceEditorMode::IsContextRestrictionCommandEnabled)); } bool ULevelInstanceEditorMode::IsSelectionDisallowed(AActor* InActor, bool bInSelection) const { UWorld* World = InActor->GetWorld(); const bool bRestrict = bInSelection && IsContextRestrictedForWorld(World); if (bRestrict) { check(World); if (ULevelInstanceSubsystem* LevelInstanceSubsystem = UWorld::GetSubsystem(World)) { const ILevelInstanceInterface* PropertyOverrideLevelInstance = LevelInstanceSubsystem->GetEditingPropertyOverridesLevelInstance(); const ILevelInstanceInterface* EditLevelInstance = LevelInstanceSubsystem->GetEditingLevelInstance(); if (ILevelInstanceInterface* LevelInstance = Cast(InActor)) { // If Actor is itself a Level Instance and is one of the edits, allow selection if (LevelInstance == PropertyOverrideLevelInstance || LevelInstance == EditLevelInstance) { return false; } } const ILevelInstanceInterface* ParentLevelInstance = LevelInstanceSubsystem->GetParentLevelInstance(InActor); auto IsAncestorOrSelf = [LevelInstanceSubsystem](const ILevelInstanceInterface* LevelInstance, const ILevelInstanceInterface* Ancestor) { while (LevelInstance != nullptr) { if (LevelInstance == Ancestor) { return true; } LevelInstance = LevelInstanceSubsystem->GetParentLevelInstance(CastChecked(LevelInstance)); } return false; }; // If we have a PropertyOverride Edit in progress, actor can be selected if it is part of the PropertyOverrides hierarchy if (PropertyOverrideLevelInstance) { return !IsAncestorOrSelf(ParentLevelInstance, PropertyOverrideLevelInstance); } // If we have a Edit in progress, actor can be selected if it is part of the Edit hierarchy if (EditLevelInstance) { return !IsAncestorOrSelf(ParentLevelInstance, EditLevelInstance); } return false; } } return bRestrict; } void ULevelInstanceEditorMode::ExitModeCommand() { // Ignore command when any modal window is open if (FSlateApplication::IsInitialized() && FSlateApplication::Get().GetActiveModalWindow().IsValid()) { return; } if (ILevelInstanceEditorModule* EditorModule = FModuleManager::GetModulePtr("LevelInstanceEditor")) { EditorModule->BroadcastTryExitEditorMode(); } } void ULevelInstanceEditorMode::ToggleContextRestrictionCommand() { bContextRestriction = !bContextRestriction; UpdateEngineShowFlags(); } bool ULevelInstanceEditorMode::IsContextRestrictionCommandEnabled() const { return bContextRestriction; } bool ULevelInstanceEditorMode::IsContextRestrictedForWorld(UWorld* InWorld) const { if (ULevelInstanceSubsystem* LevelInstanceSubsystem = InWorld? InWorld->GetSubsystem() : nullptr) { if (ILevelInstanceInterface* EditingPropertyOverrides = LevelInstanceSubsystem->GetEditingPropertyOverridesLevelInstance()) { // Always restrict outside selection while editing property overrides return true; } else if (ILevelInstanceInterface* EditingLevelInstance = LevelInstanceSubsystem->GetEditingLevelInstance()) { return bContextRestriction && LevelInstanceSubsystem->GetLevelInstanceLevel(EditingLevelInstance) == InWorld->GetCurrentLevel(); } } return false; } #undef LOCTEXT_NAMESPACE