2016-12-08 08:52:44 -05:00
|
|
|
// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved.
|
2014-03-14 14:13:41 -04:00
|
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
|
Copying //UE4/Dev-Build to //UE4/Dev-Main (Source: //UE4/Dev-Build @ 3209340)
#lockdown Nick.Penwarden
#rb none
==========================
MAJOR FEATURES + CHANGES
==========================
Change 3209340 on 2016/11/23 by Ben.Marsh
Convert UE4 codebase to an "include what you use" model - where every header just includes the dependencies it needs, rather than every source file including large monolithic headers like Engine.h and UnrealEd.h.
Measured full rebuild times around 2x faster using XGE on Windows, and improvements of 25% or more for incremental builds and full rebuilds on most other platforms.
* Every header now includes everything it needs to compile.
* There's a CoreMinimal.h header that gets you a set of ubiquitous types from Core (eg. FString, FName, TArray, FVector, etc...). Most headers now include this first.
* There's a CoreTypes.h header that sets up primitive UE4 types and build macros (int32, PLATFORM_WIN64, etc...). All headers in Core include this first, as does CoreMinimal.h.
* Every .cpp file includes its matching .h file first.
* This helps validate that each header is including everything it needs to compile.
* No engine code includes a monolithic header such as Engine.h or UnrealEd.h any more.
* You will get a warning if you try to include one of these from the engine. They still exist for compatibility with game projects and do not produce warnings when included there.
* There have only been minor changes to our internal games down to accommodate these changes. The intent is for this to be as seamless as possible.
* No engine code explicitly includes a precompiled header any more.
* We still use PCHs, but they're force-included on the compiler command line by UnrealBuildTool instead. This lets us tune what they contain without breaking any existing include dependencies.
* PCHs are generated by a tool to get a statistical amount of coverage for the source files using it, and I've seeded the new shared PCHs to contain any header included by > 15% of source files.
Tool used to generate this transform is at Engine\Source\Programs\IncludeTool.
[CL 3209342 by Ben Marsh in Main branch]
2016-11-23 15:48:37 -05:00
|
|
|
#include "CoreMinimal.h"
|
|
|
|
|
#include "Modules/ModuleManager.h"
|
|
|
|
|
#include "Widgets/SWindow.h"
|
|
|
|
|
#include "UnrealEdMisc.h"
|
|
|
|
|
#include "Misc/App.h"
|
|
|
|
|
#include "Framework/Application/SlateApplication.h"
|
|
|
|
|
#include "Framework/Docking/TabManager.h"
|
|
|
|
|
#include "Framework/Docking/LayoutService.h"
|
|
|
|
|
#include "EngineGlobals.h"
|
|
|
|
|
#include "Toolkits/AssetEditorManager.h"
|
|
|
|
|
#include "Editor/UnrealEdEngine.h"
|
|
|
|
|
#include "EditorModeManager.h"
|
|
|
|
|
#include "EditorModes.h"
|
|
|
|
|
#include "FileHelpers.h"
|
|
|
|
|
#include "UnrealEdGlobals.h"
|
|
|
|
|
#include "LevelEditor.h"
|
|
|
|
|
#include "ILevelViewport.h"
|
|
|
|
|
#include "MainFrameLog.h"
|
|
|
|
|
|
|
|
|
|
const FText StaticGetApplicationTitle( const bool bIncludeGameName );
|
2014-03-14 14:13:41 -04:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Helper class that handles talking to the Slate App Manager.
|
|
|
|
|
*/
|
|
|
|
|
class FMainFrameHandler : public TSharedFromThis<FMainFrameHandler>
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Shuts down the Editor.
|
|
|
|
|
*/
|
|
|
|
|
void ShutDownEditor( TSharedRef<SDockTab> TabBeingClosed )
|
|
|
|
|
{
|
|
|
|
|
ShutDownEditor();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Shuts down the Editor.
|
|
|
|
|
*/
|
2014-10-14 22:50:06 -04:00
|
|
|
void ShutDownEditor( );
|
2014-03-14 14:13:41 -04:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Checks whether the main frame tab can be closed.
|
|
|
|
|
*
|
|
|
|
|
* @return true if the tab can be closed, false otherwise.
|
|
|
|
|
*/
|
|
|
|
|
bool CanCloseTab()
|
|
|
|
|
{
|
|
|
|
|
if ( GIsRequestingExit )
|
|
|
|
|
{
|
|
|
|
|
UE_LOG(LogMainFrame, Warning, TEXT("MainFrame: Shutdown already in progress when CanCloseTab was queried, approve tab for closure."));
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return CanCloseEditor();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Checks whether the Editor tab can be closed.
|
|
|
|
|
*
|
|
|
|
|
* @return true if the Editor can be closed, false otherwise.
|
|
|
|
|
*/
|
|
|
|
|
bool CanCloseEditor()
|
|
|
|
|
{
|
|
|
|
|
if ( FSlateApplication::IsInitialized() && !FSlateApplication::Get().IsNormalExecution() )
|
|
|
|
|
{
|
|
|
|
|
// DEBUGGER EXIT PATH
|
|
|
|
|
|
|
|
|
|
// The debugger is running we cannot actually close now.
|
|
|
|
|
// We will stop the debugger and enque a request to close the editor on the next frame.
|
|
|
|
|
|
|
|
|
|
// Stop debugging.
|
|
|
|
|
FSlateApplication::Get().LeaveDebuggingMode();
|
|
|
|
|
|
|
|
|
|
// Defer the call RequestCloseEditor() till next tick.
|
|
|
|
|
GEngine->DeferredCommands.Add( TEXT("CLOSE_SLATE_MAINFRAME") );
|
|
|
|
|
|
|
|
|
|
// Cannot exit right now.
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2015-04-01 03:03:18 -04:00
|
|
|
else if (GIsSavingPackage || IsGarbageCollecting())
|
2014-03-14 14:13:41 -04:00
|
|
|
{
|
|
|
|
|
// SAVING/GC PATH
|
|
|
|
|
|
|
|
|
|
// We're currently saving or garbage collecting and can't close the editor just yet.
|
|
|
|
|
// We will have to wait and try to request to close the editor on the next frame.
|
|
|
|
|
|
|
|
|
|
// Defer the call RequestCloseEditor() till next tick.
|
|
|
|
|
GEngine->DeferredCommands.Add( TEXT("CLOSE_SLATE_MAINFRAME") );
|
|
|
|
|
|
|
|
|
|
// Cannot exit right now.
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// NORMAL EXIT PATH
|
|
|
|
|
|
|
|
|
|
// Unattented mode can always exit.
|
|
|
|
|
if (FApp::IsUnattended())
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// We can't close if lightmass is currently building
|
|
|
|
|
if (GUnrealEd->WarnIfLightingBuildIsCurrentlyRunning()) {return false;}
|
|
|
|
|
|
|
|
|
|
bool bOkToExit = true;
|
|
|
|
|
|
|
|
|
|
// Check if level Mode is open this does PostEditMove processing on actors when it closes so need to do this first before save dialog
|
2014-06-18 10:16:16 -04:00
|
|
|
if( GLevelEditorModeTools().IsModeActive( FBuiltinEditorModes::EM_Level ) ||
|
|
|
|
|
GLevelEditorModeTools().IsModeActive( FBuiltinEditorModes::EM_StreamingLevel) )
|
2014-03-14 14:13:41 -04:00
|
|
|
{
|
2014-07-31 06:08:01 -04:00
|
|
|
GLevelEditorModeTools().DeactivateMode(FBuiltinEditorModes::EM_Level);
|
|
|
|
|
GLevelEditorModeTools().DeactivateMode(FBuiltinEditorModes::EM_StreamingLevel);
|
2014-03-14 14:13:41 -04:00
|
|
|
bOkToExit = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Can we close all the major tabs? They have sub-editors in them that might want to not close
|
|
|
|
|
{
|
|
|
|
|
// Ignore the LevelEditor tab; it invoked this function in the first place.
|
|
|
|
|
TSet< TSharedRef<SDockTab> > TabsToIgnore;
|
|
|
|
|
if ( MainTabPtr.IsValid() )
|
|
|
|
|
{
|
|
|
|
|
TabsToIgnore.Add( MainTabPtr.Pin().ToSharedRef() );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bOkToExit = bOkToExit && FGlobalTabmanager::Get()->CanCloseManager(TabsToIgnore);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Prompt for save and quit only if we did not launch a gameless rocket exe or are in demo mode
|
|
|
|
|
if ( FApp::HasGameName() && !GIsDemoMode )
|
|
|
|
|
{
|
|
|
|
|
// Prompt the user to save packages/maps.
|
|
|
|
|
bool bHadPackagesToSave = false;
|
|
|
|
|
{
|
|
|
|
|
const bool bPromptUserToSave = true;
|
|
|
|
|
const bool bSaveMapPackages = true;
|
|
|
|
|
const bool bSaveContentPackages = true;
|
|
|
|
|
const bool bFastSave = false;
|
|
|
|
|
const bool bNotifyNoPackagesSaved = false;
|
2015-02-27 04:17:41 -05:00
|
|
|
const bool bCanBeDeclined = true;
|
|
|
|
|
bOkToExit = bOkToExit && FEditorFileUtils::SaveDirtyPackages(bPromptUserToSave, bSaveMapPackages, bSaveContentPackages, bFastSave, bNotifyNoPackagesSaved, bCanBeDeclined, &bHadPackagesToSave);
|
2014-03-14 14:13:41 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If there were packages to save, or switching project, then the user already had a chance to bail out of exiting.
|
|
|
|
|
if ( !bOkToExit && !bHadPackagesToSave && FUnrealEdMisc::Get().GetPendingProjectName().IsEmpty() )
|
|
|
|
|
{
|
|
|
|
|
FUnrealEdMisc::Get().ClearPendingProjectName();
|
|
|
|
|
FUnrealEdMisc::Get().AllowSavingLayoutOnClose(true);
|
|
|
|
|
FUnrealEdMisc::Get().ForceDeletePreferences(false);
|
|
|
|
|
FUnrealEdMisc::Get().ClearConfigRestoreFilenames();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return bOkToExit;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CloseRootWindowOverride( const TSharedRef<SWindow>& WindowBeingClosed )
|
|
|
|
|
{
|
|
|
|
|
if (CanCloseEditor())
|
|
|
|
|
{
|
|
|
|
|
ShutDownEditor();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Method that handles the generation of the mainframe, given the window it resides in,
|
|
|
|
|
* and a string which determines the initial layout of its primary dock area.
|
|
|
|
|
*/
|
|
|
|
|
void OnMainFrameGenerated( const TSharedPtr<SDockTab>& MainTab, const TSharedRef<SWindow>& InRootWindow )
|
|
|
|
|
{
|
|
|
|
|
TSharedRef<FGlobalTabmanager> GlobalTabManager = FGlobalTabmanager::Get();
|
|
|
|
|
|
2014-08-18 06:17:55 -04:00
|
|
|
if (MainTab.IsValid())
|
|
|
|
|
{
|
|
|
|
|
GlobalTabManager->SetMainTab(MainTab.ToSharedRef());
|
|
|
|
|
}
|
2014-08-15 16:14:44 -04:00
|
|
|
|
2014-03-14 14:13:41 -04:00
|
|
|
// Persistent layouts should get stored using the specified method.
|
2014-05-15 17:34:02 -04:00
|
|
|
GlobalTabManager->SetOnPersistLayout(FTabManager::FOnPersistLayout::CreateRaw(this, &FMainFrameHandler::HandleTabManagerPersistLayout));
|
2014-03-14 14:13:41 -04:00
|
|
|
|
|
|
|
|
const bool bIncludeGameName = true;
|
|
|
|
|
GlobalTabManager->SetApplicationTitle( StaticGetApplicationTitle( bIncludeGameName ) );
|
|
|
|
|
|
|
|
|
|
InRootWindow->SetRequestDestroyWindowOverride( FRequestDestroyWindowOverride::CreateRaw( this, &FMainFrameHandler::CloseRootWindowOverride ) );
|
|
|
|
|
|
|
|
|
|
MainTabPtr = MainTab;
|
|
|
|
|
RootWindowPtr = InRootWindow;
|
|
|
|
|
|
|
|
|
|
EnableTabClosedDelegate();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Shows the main frame window. Call this after you've setup initial layouts to reveal the window
|
|
|
|
|
*
|
2016-03-11 17:29:00 -05:00
|
|
|
* @param bStartImmersive True to force a main frame viewport into immersive mode
|
|
|
|
|
* @param bStartPIE True to start a PIE session right away
|
2014-03-14 14:13:41 -04:00
|
|
|
*/
|
2016-03-11 17:29:00 -05:00
|
|
|
void ShowMainFrameWindow(TSharedRef<SWindow> Window, const bool bStartImmersive, const bool bStartPIE) const
|
2014-03-14 14:13:41 -04:00
|
|
|
{
|
|
|
|
|
// Make sure viewport windows are maximized/immersed if they need to be
|
|
|
|
|
FLevelEditorModule& LevelEditor = FModuleManager::GetModuleChecked< FLevelEditorModule >( TEXT( "LevelEditor" ) );
|
|
|
|
|
|
2016-03-11 17:29:00 -05:00
|
|
|
if( bStartPIE )
|
2014-03-14 14:13:41 -04:00
|
|
|
{
|
|
|
|
|
// Kick off an immersive PIE session immediately!
|
2016-03-11 17:29:00 -05:00
|
|
|
|
|
|
|
|
if( bStartImmersive )
|
|
|
|
|
{
|
|
|
|
|
// When in immersive play in editor, toggle game view on the active viewport
|
|
|
|
|
const bool bForceGameView = true;
|
|
|
|
|
|
|
|
|
|
// Start level viewport initially in immersive mode
|
|
|
|
|
LevelEditor.GoImmersiveWithActiveLevelViewport( bForceGameView );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LevelEditor.StartPlayInEditorSession();
|
2014-03-14 14:13:41 -04:00
|
|
|
Window->ShowWindow();
|
2016-03-11 17:29:00 -05:00
|
|
|
// Ensure the window is at the front or else we could end up capturing and locking the mouse to a window that isn't visible
|
2014-03-14 14:13:41 -04:00
|
|
|
bool bForceWindowToFront = true;
|
|
|
|
|
Window->BringToFront( bForceWindowToFront );
|
|
|
|
|
|
|
|
|
|
// Need to register after the window is shown or else we cant capture the mouse
|
|
|
|
|
TSharedPtr<ILevelViewport> Viewport = LevelEditor.GetFirstActiveViewport();
|
|
|
|
|
Viewport->RegisterGameViewportIfPIE();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2016-03-11 17:29:00 -05:00
|
|
|
if( bStartImmersive )
|
|
|
|
|
{
|
|
|
|
|
// When in immersive play in editor, toggle game view on the active viewport
|
|
|
|
|
const bool bForceGameView = true;
|
|
|
|
|
|
|
|
|
|
// Start level viewport initially in immersive mode
|
|
|
|
|
LevelEditor.GoImmersiveWithActiveLevelViewport( bForceGameView );
|
|
|
|
|
}
|
|
|
|
|
|
2014-03-14 14:13:41 -04:00
|
|
|
// Show the window!
|
|
|
|
|
Window->ShowWindow();
|
|
|
|
|
|
2016-03-11 17:29:00 -05:00
|
|
|
if( bStartImmersive )
|
|
|
|
|
{
|
|
|
|
|
// Ensure the window is at the front or else we could end up capturing and locking the mouse to a window that isn't visible
|
|
|
|
|
bool bForceWindowToFront = true;
|
|
|
|
|
Window->BringToFront( bForceWindowToFront );
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// Focus the level editor viewport
|
|
|
|
|
LevelEditor.FocusViewport();
|
2014-03-14 14:13:41 -04:00
|
|
|
|
2016-03-11 17:29:00 -05:00
|
|
|
// Restore any assets we had open. Note we don't do this on immersive PIE as its annoying to the user.
|
|
|
|
|
FAssetEditorManager::Get().RequestRestorePreviouslyOpenAssets();
|
|
|
|
|
}
|
2014-03-14 14:13:41 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** Gets the parent window of the mainframe */
|
|
|
|
|
TSharedPtr<SWindow> GetParentWindow() const
|
|
|
|
|
{
|
|
|
|
|
return RootWindowPtr.Pin();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** Sets the reference to the main tab */
|
|
|
|
|
void SetMainTab(const TSharedRef<SDockTab>& MainTab)
|
|
|
|
|
{
|
|
|
|
|
MainTabPtr = MainTab;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** Enables the delegate responsible for shutting down the editor when the main tab is closed */
|
2014-10-14 22:50:06 -04:00
|
|
|
void EnableTabClosedDelegate();
|
2014-03-14 14:13:41 -04:00
|
|
|
|
|
|
|
|
/** Disables the delegate responsible for shutting down the editor when the main tab is closed */
|
2014-10-14 22:50:06 -04:00
|
|
|
void DisableTabClosedDelegate();
|
2014-03-14 14:13:41 -04:00
|
|
|
|
2014-05-15 17:34:02 -04:00
|
|
|
private:
|
|
|
|
|
|
|
|
|
|
// Callback for persisting the Level Editor's layout.
|
|
|
|
|
void HandleTabManagerPersistLayout( const TSharedRef<FTabManager::FLayout>& LayoutToSave )
|
|
|
|
|
{
|
|
|
|
|
FLayoutSaveRestore::SaveToConfig(GEditorLayoutIni, LayoutToSave);
|
|
|
|
|
}
|
2014-03-14 14:13:41 -04:00
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
|
|
|
|
|
/** Editor main frame window */
|
|
|
|
|
TWeakPtr<SDockTab> MainTabPtr;
|
|
|
|
|
|
|
|
|
|
/** The window that all of the editor is parented to. */
|
|
|
|
|
TWeakPtr<SWindow> RootWindowPtr;
|
|
|
|
|
};
|