Files
UnrealEngineUWP/Engine/Source/Editor/MainFrame/Private/MainFrameModule.cpp
Marc Audy ad1d2f130f Copying //UE4/Dev-Framework to //UE4/Dev-Main (Source: //UE4/Dev-Framework @ 2994668)
#lockdown Nick.Penwarden

==========================
MAJOR FEATURES + CHANGES
==========================

Change 2967465 on 2016/05/05 by Marc.Audy

	Fix VS2015 shadow variables fixes

Change 2970637 on 2016/05/09 by Martin.Wilson

	Fix incorrect conflict resolve in merge from main

Change 2976393 on 2016/05/12 by Zak.Middleton

	#ue4 - Set AudioComponent bUseAttachParentBounds=true to reduce cost of transform updates (avoids virtual CalcBounds() when transform changes).

	#tests PIE w/ audio

Change 2976770 on 2016/05/13 by Lina.Halper

	Improvement on mirroring fix branch

	#code review: Zak.Middleton

Change 2976774 on 2016/05/13 by Lukasz.Furman

	fixed missing memory callbacks for instanced behavior tree nodes
	#jira UE-30305

Change 2976775 on 2016/05/13 by Lukasz.Furman

	fixed multiple calls to behavior tree's instance cleanup
	#jira UE-30593

Change 2976801 on 2016/05/13 by Jon.Nabozny

	Add an optional argument FSkeletalMeshMerge. When set to EMeshBufferAccess::ForceCPUAndGPU, keeps a reference to the vertex buffer on CPU (e.g. for spawning particle effects).

	#JIRA UE-30405

Change 2976985 on 2016/05/13 by Jon.Nabozny

	Fix initializer list ordering for FSkeletalMeshMerge.

Change 2977532 on 2016/05/13 by Marc.Audy

	PR #2348: [Local Multiplayer] Gamepad player assignment improvements (Contributed by kukiric)
	#jira UE-30162

Change 2977637 on 2016/05/13 by Marc.Audy

	Add Get/Set controller ID for a player in gameplay statics
	#jira UE-28718

Change 2979387 on 2016/05/16 by Jon.Nabozny

	Initialize FBox used to store results for CalculateQuatACF96Bounds.

	#JIRA UE-30846

Change 2979968 on 2016/05/17 by bruce.nesbit

	Added comment in FCanvasLineItem to warn only SE_BLEND_Opaque will be used when rendering.

Change 2979969 on 2016/05/17 by bruce.nesbit

	Added comment in AddLine/AddPoint to warn only SE_BLEND_Opaque will be used when rendering.

Change 2980271 on 2016/05/17 by Lina.Halper

	Improved comment

	#code review: Benn.Gallagher

Change 2980317 on 2016/05/17 by Lukasz.Furman

	removing NavCollision from static mesh on property change and PostLoad if static mesh is not supposed to have one
	#ue4

Change 2980717 on 2016/05/17 by Zak.Middleton

	#ue4 - Optimize UCapsuleComponent::CalcBounds() to remove sqrt and use tighter bounding sphere radius.

Change 2981193 on 2016/05/17 by Lukasz.Furman

	fixed missing observers in behavior tree when dynamic subtree is changed while waiting for full restart (out of nodes)
	#ue4

Change 2981927 on 2016/05/18 by Lina.Halper

	- Remove vertex animation code
	  - Removing UVertexAnimation
	  - Fixed reinitialization issue that was triggered by SetVertexAnimation

	- todo: consolidate UMorphtarget and UVertexAnimBase

	#code review: James.Golding, Martin.Wilson

Change 2981957 on 2016/05/18 by Lina.Halper

	Add recursive stack check on update animation

	#code review: Martin.Wilson

Change 2982116 on 2016/05/18 by Benn.Gallagher

	Removed optimize macros accidentally left after bounds extension feature for skel meshes

Change 2982255 on 2016/05/18 by Jon.Nabozny

	FSkeletalMeshMerge constructor "MeshBufferAccess" default should be EMeshBufferAccess:Default instead of EMeshBufferAccess::ForceCPUAndGPU.

Change 2982607 on 2016/05/18 by Marc.Audy

	Cleanup places calling GetWorld() multiple times

Change 2982621 on 2016/05/18 by Marc.Audy

	Make UActorComponent::GetWorld final and inlined to avoid unnecessary function calls
	Put uncached logic in to a separate function

Change 2983424 on 2016/05/19 by Marc.Audy

	Minor tweaks to reduce GetWorld calls

Change 2983465 on 2016/05/19 by Lina.Halper

	Combine VertexAnimBase and MorphTarget to just MorphTarget

	 - VertexAnimBase is gone
	 - Modified most of VertexAnim to MorphTarget
	 - Removed state, time related data

	#code review: James.Golding, Rolando.Caloca

Change 2983609 on 2016/05/19 by Marc.Audy

	Inline AActor::GetLevel
	Half GetWorld() calls from AActor::GetNetMode()

Change 2983772 on 2016/05/19 by Marc.Audy

	Fix Mac compile

Change 2983931 on 2016/05/19 by Marc.Audy

	Remove pointless AccelMouse function

Change 2984061 on 2016/05/19 by Marc.Audy

	Reorg some headers to fix compilation issues

Change 2984409 on 2016/05/19 by Aaron.McLeran

	#jira UE-31049 Updating the Oculus Audio SDK to vs 1.02

	Implementing 2984316 from Releases/4.12 to Dev-Framework

Change 2984574 on 2016/05/19 by Aaron.McLeran

	Fix for platform headroom scalar. Using correct dB to linear formula (not one for power)

	dB = 20 * log(Linear), not dB = 10 * log(Linear)

Change 2985041 on 2016/05/20 by Jon.Nabozny

	ConvertQueryOverlap only returns the base actor if multiple actors have bSimulatePhysics enabled and are welded together.

	#JIRA UE-30484

Change 2985118 on 2016/05/20 by Marc.Audy

	Another attempt to convince Mac to build

Change 2985192 on 2016/05/20 by Marc.Audy

	Properly forward declare ABrush

Change 2985724 on 2016/05/20 by Zak.Middleton

	#ue4 - Optimize NaN and Infinite checks for FVector, FQuat, FRotator, FMatrix, FTransform. SIMD version VectorContainsNaNOrInfinite() also optimized on relevant platforms. Added startup tests for VectorContainsNaNOrInfinite().

	- All our "ContainsNaN()" tests are in fact "IsNaN() || IsInfinite()", which is the same as "!IsFinite()", so exploited this to simplify the tests. Both NaN and +/-Inf are not finite (http://en.cppreference.com/w/cpp/numeric/math/isfinite). In the future we should rename ContainsNaN().
	- Still need to audit some uses in shipping configs.

	#jira UE-30999

Change 2986016 on 2016/05/20 by Zak.Middleton

	#ue4 - Fix uint32 used for int32 values. Behavior was unaffected.

Change 2986017 on 2016/05/20 by Zak.Middleton

	#ue4 - Fix overlaps being dropped from within a FScopedMoveUpdate when rotation occurs. Remove invalid assert.

Change 2986833 on 2016/05/23 by Zak.Middleton

	#ue4 - Move ETeleportType from ActorComponent.h to EngineTypes.h. Add comment to FHitResult for ImpactPoint when it's penetrating.

Change 2986916 on 2016/05/23 by Rolando.Caloca

	DF - GPU morph targets proof of concept
	- Disabled by default
	- Not compatible with gpu skin cache
	- No extra memory required yet until it's used; creates buffers per frame (very slow!)

Change 2987539 on 2016/05/23 by Rolando.Caloca

	DF - Remove unused member and downgrade FActiveMorphTarget to not be a USTRUCT

Change 2987981 on 2016/05/24 by James.Golding

	PR #2162 : Exported AAudioVolume so that projects can derive custom classes.
	https://github.com/EpicGames/UnrealEngine/pull/2162
	#github 2162
	#jira UE-28533

Change 2987982 on 2016/05/24 by James.Golding

	PR #2318 : Fix memory allocation in CustomMeshComponent.cpp
	https://github.com/EpicGames/UnrealEngine/pull/2318
	#github 2318
	#jira UE-29864

Change 2987983 on 2016/05/24 by James.Golding

	Merging engine changes back from GDC demo:
	- Export FFIRFilterTimeBased from Engine module
	- Add FFIRFilterTimeBased::SetWindowDuration
	- Add FBaseCompactPose::CopyBonesTo

Change 2987984 on 2016/05/24 by James.Golding

	UE-30137 No longer include collision in StatiMeshComponent bounds (bounds no longer user for any collision calculation)

Change 2987985 on 2016/05/24 by James.Golding

	UE-27801 Export ConvertToCollisionChannel, ConvertToObjectType, and ConvertToTraceType members of UCollisionProfile

Change 2987987 on 2016/05/24 by James.Golding

	OR-17910 : Support 'show collision' in Test configuration

Change 2988123 on 2016/05/24 by Jon.Nabozny

	Prevent FBodyInstance::Weld causing duplicate PhsyXShapes to be created / added to ShapeToBodiesMap when toggling SimulatePhysics on PrimitiveComponent.

	#JIRA UE-31189

Change 2988449 on 2016/05/24 by Rolando.Caloca

	DF - Split FActiveMorphTarget's weight into its own array in prep for GPU friendly data

Change 2988485 on 2016/05/24 by Jon.Nabozny

	Swap order of setRigidBodyFlag and setRigidDynamicFlag inside UpdateInstanceSimulatePhysics to prevent PhysX error about Kinematic bodies not using CCD.

	#JIRA UE-30993

Change 2988969 on 2016/05/24 by Rolando.Caloca

	DF - GPU morph targets
	- Enable using r.MorphTarget.Mode 1

Change 2989645 on 2016/05/25 by Marc.Audy

	Apply CL# 2989481 to Dev-Framework
	#jira UE-31055

Change 2989987 on 2016/05/25 by Wes.Hunt

	Redo of CL#2982707 2982716 2982723 2983780 2983864 from //Orion/Dev-General in preparation for continuing Analytics refactor in a Dev branch.

	AnalyticsET support for arbitrary Json events.
	* AnalyticsET supports a new API, RecordEventJson.
	* API supports rvalue refs to avoid unnecessary copies of the attribute array.
	#AUTOMERGE using branch Orion-Dev-General-To-UE4-Dev-Framework of change#2982707 by Wes.Hunt on 2016/05/18 17:22:20.

	Remove Analytics code to divert legacy code to source data collector.
	#AUTOMERGE using branch Orion-Dev-General-To-UE4-Dev-Framework of change#2982716 by Wes.Hunt on 2016/05/18 17:27:25.

	Analytics no longer adds IsEditor attribute to all events. Wasn't actually used by anyone anymore.
	#AUTOMERGE using branch Orion-Dev-General-To-UE4-Dev-Framework of change#2982723 by Wes.Hunt on 2016/05/18 17:29:40.

	Modernize FAnalyticsEventAttribute usage.

	Replaced FAnalyticsEventAttribute various ctors with a perfect forwarding one that can convert them to strings.
	* The Name must be convertible to a string
	* The value must be convertible to a string via an AnalyticsConversion::ToString() overload.
	* Added/expanded the supported conversions to strings to analytics attribute values. See AnalyticsConversion.h which contains all the previously supported conversions and more.

	Added MakeAnalyticsEventAttributeArray(), which uses variadic templates to create an array of event attributes inline, which can be passed to RecordEvent[Json] and efficiently taken ownership of:
	    RecordEvent("EventName", MakeAnalyticsEventAttributeArray(
	        "Attr1", false,
	        "Attr2", 42.0,
	        "Attr3",  SomeMap,
	        "Attr4", SomeArray);

	#AUTOMERGE using branch Orion-Dev-General-To-UE4-Dev-Framework of change#2983780 by Wes.Hunt on 2016/05/19 13:51:48.

	Added missing assignment copy/move ops to FAnalyticsEventAttribute. Doh, should have looked at more usages of PLATFORM_COMPILER_HAS_DEFAULTED_FUNCTIONS...
	#AUTOMERGE using branch Orion-Dev-General-To-UE4-Dev-Framework of change#2983864 by Wes.Hunt on 2016/05/19 14:17:05.

Change 2989988 on 2016/05/25 by Wes.Hunt

	Fix usage of FAnalyticsEventAttribute constructor using a bitfield that was invalidated by the change to make FAnalyticsEventAttribute use a perfect forwarding constructor. bitfields cannot be perfect-forwarded... :(

Change 2990493 on 2016/05/25 by Joe.Graf

	Added tooltips to the collision analyzer's buttons

	#CodeReview: james.golding

Change 2991064 on 2016/05/26 by James.Golding

	- Remove many Animation headers from Engine.h
	- Remove AnimationAsset.h from SkeletalMeshComponent.h, Character.h, CharacterMovementComponent.h

Change 2991113 on 2016/05/26 by Benn.Gallagher

	Fixed edge case in random sequence player where we might trigger an extra loop when waiting on a blend to finish. And made it impossible for a shuffle list to start with the animation that is currently playing (seemingly duplicating the anim).

Change 2991163 on 2016/05/26 by Rolando.Caloca

	DF - Rename and refactor some morph target compute shader in prep for interop with skin cache

Change 2991167 on 2016/05/26 by Jon.Nabozny

	Add `#include "DataTable.h"` to GameplayTagsManager.h. FGameplayTagTableRow is derived from FTableRowBase which isn't necessarily included. This issue is hidden in most cases as "Engine.h" includes "DataTable.h".

Change 2991183 on 2016/05/26 by Wes.Hunt

	Disable general forwarding constructor for AnalyticsEventAttribute for non arithmetic types, so they are free to choose other overloads more appropriately.

Change 2991199 on 2016/05/26 by Wes.Hunt

	Drastically reducing the headers dependencies on analytics headers. Analytics headers no longer appear in PCH files, and rarely if ever appear in a header file.

	IAnalyticsProviderModule.h only touches 8 source files.
	Analytics.h only touches 8 source files.
	IAnalyticsProvider.h only touches 5 headers and 97 source files.
	AnalyticsET.h only touches 12 source files.

Change 2991301 on 2016/05/26 by James.Golding

	Fix CIS for Fortnite

Change 2991319 on 2016/05/26 by James.Golding

	Fix CIS for Orion

Change 2991373 on 2016/05/26 by Joe.Graf

	Tweaked the tooltip text for the collision analyzer record button to be correct for both states
	Added a common button style so that the buttons have a consistent look

	#CodeReview: james.golding

Change 2991401 on 2016/05/26 by James.Golding

	Fix UT CIS

Change 2991406 on 2016/05/26 by James.Golding

	Fix Ocean CIS

Change 2991491 on 2016/05/26 by Lina.Halper

	Moved MorphTarget.h

	- Checked in modified functions fo AnimationRuntime for other features coming up
	 - Should not change any behavior of existing content

	#code review: James.Golding, Rolando.Caloca

Change 2991494 on 2016/05/26 by Wes.Hunt

	Fix for Unity error in AnalyticsET module after hedaer dependency reduction

Change 2991503 on 2016/05/26 by Jon.Nabozny

	Fix issue where FConstraintInstance (inside UPhysicsConstraintComponent) is not editable in InstanceEditor but is editable in BlueprintEditor.

	#JIRA UE-31267

Change 2991562 on 2016/05/26 by Zak.Middleton

	#ue4 - Reduce allocations during movement and overlap queries and when grabbing shapes from physx actors.

Change 2991586 on 2016/05/26 by James.Golding

	More CIS fixes for Orion and Fortnite

Change 2991673 on 2016/05/26 by Wes.Hunt

	Another non-unity fix for Analytics include dependency reduction.

Change 2991733 on 2016/05/26 by Zak.Middleton

	#dev - Test map, 50 walking dudes.

Change 2991781 on 2016/05/26 by Lina.Halper

	Back out revision 15 from //UE4/Dev-Framework/Engine/Source/Runtime/Engine/Private/Animation/AnimationRuntime.cpp

	- Back out a part of changes that I didn't mean to check in.

Change 2991922 on 2016/05/26 by Zak.Middleton

	#ue4 - Maybe fix Mac build.

Change 2991957 on 2016/05/26 by Joe.Graf

	Fixed the collision analyzer file open text (said project instead of collision)

Change 2991991 on 2016/05/26 by Lina.Halper

	Fix compile error

Change 2992089 on 2016/05/26 by Zak.Middleton

	#ue4 - Fix Mac/PS4 build.

Change 2992108 on 2016/05/26 by Wes.Hunt

	Yet another non-unity fix for Analytics header inclusion reduction.

Change 2992190 on 2016/05/26 by Zak.Middleton

	#ue4 - Mark FHitResult, FOverlapResult, FOverlapInfo as POD types. Avoids destructors etc when in TArrays.

Change 2992593 on 2016/05/27 by Martin.Wilson

	Build fixes for non editor platforms

Change 2992885 on 2016/05/27 by Rolando.Caloca

	DF - Fix crash on thumbnails
	#jira UE-31398

Change 2993058 on 2016/05/27 by Lukasz.Furman

	fixed behavior tree getting stuck on ResumeLogic call
	#jira OR-22498

Change 2993064 on 2016/05/27 by Zak.Middleton

	#ue4 - Fix root motion network corrections not clearing root motion data.

	udn: https://udn.unrealengine.com/questions/294985/jittering-in-character-movement-during-networked-m.html
	#jira UE-31316

Change 2993215 on 2016/05/27 by Lukasz.Furman

	gameplay debugger fixes: navmesh rendering is not hidden after disabling tool, player stuck in spectator mode after disabling tool, confusing version description for categories without data packs
	added replicated input bindings for debugger's categories
	#ue4

Change 2993521 on 2016/05/27 by Zak.Middleton

	#ue4 - Reduce allocations in UI Canvas items.

Change 2993995 on 2016/05/30 by Mieszko.Zielinski

	Temporary fix for BBKeySelector not handling properly multiple UObject subtypes #UE4

	#jira UE-31435

Change 2993998 on 2016/05/30 by Mieszko.Zielinski

	Improves handling of a special case in EQS score normalization, where all items have the same score #UE4

	We used to set the normalized score of 1 for all items, which was counter intuitive if all items have scored 0 in an unnormalized test. The improve handling detects that and assigns score of 0 in that case.

Change 2993999 on 2016/05/30 by Mieszko.Zielinski

	Fixed FEQSParametrizedQueryExecutionRequest converting non-BB values into EQS params wrong #UE4

Change 2994000 on 2016/05/30 by Mieszko.Zielinski

	Exposed UNavigationInvokerComponent as part of ENGINE_API so that it can be spawned procedurally in C++ in game specific code #UE4

Change 2994003 on 2016/05/30 by Mieszko.Zielinski

	Fixed naming of console variable controllin v-logging of FGameplayAttribute #UE4

	The old name was copy-pasted from somewhere.

Change 2994007 on 2016/05/30 by Mieszko.Zielinski

	Fixed unregistering listeners from perception system not clearing up all data #UE4

	Also, introduced two precisely named functions, GetCurrentlyPerceivedActors and GetKnownPerceivedActors to replace ambiguous GetPerceivedActors
	Also, renamed UAIPerceptionComponent::TActorPerceptionContainer to UAIPerceptionComponent::FActorPerceptionContainer

Change 2994475 on 2016/05/31 by Wes.Hunt

	Fix Unity build failure for analytics inclusion reduction for IOSFlurry.

[CL 2994701 by Marc Audy in Main branch]
2016-05-31 13:51:34 -04:00

890 lines
30 KiB
C++

// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved.
#include "MainFramePrivatePCH.h"
#include "CompilerResultsLog.h"
#include "Editor/EditorLiveStreaming/Public/IEditorLiveStreaming.h"
#include "Developer/HotReload/Public/IHotReload.h"
#include "NotificationManager.h"
#include "SNotificationList.h"
#include "GenericCommands.h"
#include "IAnalyticsProvider.h"
#include "EngineAnalytics.h"
DEFINE_LOG_CATEGORY(LogMainFrame);
#define LOCTEXT_NAMESPACE "FMainFrameModule"
const FText StaticGetApplicationTitle( const bool bIncludeGameName )
{
static const FText ApplicationTitle = NSLOCTEXT("UnrealEditor", "ApplicationTitle", "Unreal Editor");
if (bIncludeGameName && FApp::HasGameName())
{
FFormatNamedArguments Args;
Args.Add(TEXT("GameName"), FText::FromString( FString( FApp::GetGameName())));
Args.Add(TEXT("AppTitle"), ApplicationTitle);
const EBuildConfigurations::Type BuildConfig = FApp::GetBuildConfiguration();
if (BuildConfig != EBuildConfigurations::Shipping && BuildConfig != EBuildConfigurations::Development && BuildConfig != EBuildConfigurations::Unknown)
{
Args.Add( TEXT("Config"), EBuildConfigurations::ToText(BuildConfig));
return FText::Format( NSLOCTEXT("UnrealEditor", "AppTitleGameNameWithConfig", "{GameName} [{Config}] - {AppTitle}"), Args );
}
return FText::Format( NSLOCTEXT("UnrealEditor", "AppTitleGameName", "{GameName} - {AppTitle}"), Args );
}
return ApplicationTitle;
}
/* IMainFrameModule implementation
*****************************************************************************/
void FMainFrameModule::CreateDefaultMainFrame( const bool bStartImmersive, const bool bStartPIE )
{
if (!IsWindowInitialized())
{
FRootWindowLocation DefaultWindowLocation;
bool bEmbedTitleAreaContent = true;
bool bIsUserSizable = true;
bool bSupportsMaximize = true;
bool bSupportsMinimize = true;
FText WindowTitle;
if ( ShouldShowProjectDialogAtStartup() )
{
// Force tabs restored from layout that have no window (the LevelEditor tab) to use a docking area with
// embedded title area content. We need to override the behavior here because we're creating the actual
// window ourselves instead of letting the tab management system create it for us.
bEmbedTitleAreaContent = false;
// Do not maximize the window initially. Keep a small dialog feel.
DefaultWindowLocation.InitiallyMaximized = false;
DefaultWindowLocation.WindowSize = GetProjectBrowserWindowSize();
DefaultWindowLocation.ScreenPosition = DefaultWindowLocation.GetCenteredScreenPosition();
bIsUserSizable = true;
bSupportsMaximize = true;
bSupportsMinimize = true;
// When opening the project dialog, show "Project Browser" in the window title
WindowTitle = LOCTEXT("ProjectBrowserDialogTitle", "Unreal Project Browser");
}
else
{
if( bStartImmersive )
{
// Start maximized if we are in immersive mode
DefaultWindowLocation.InitiallyMaximized = true;
}
const bool bIncludeGameName = true;
WindowTitle = GetApplicationTitle( bIncludeGameName );
}
TSharedRef<SWindow> RootWindow = SNew(SWindow)
.AutoCenter( EAutoCenter::None )
.Title( WindowTitle )
.IsInitiallyMaximized( DefaultWindowLocation.InitiallyMaximized )
.ScreenPosition( DefaultWindowLocation.ScreenPosition )
.ClientSize( DefaultWindowLocation.WindowSize )
.CreateTitleBar( !bEmbedTitleAreaContent )
.SizingRule( bIsUserSizable ? ESizingRule::UserSized : ESizingRule::FixedSize )
.SupportsMaximize( bSupportsMaximize )
.SupportsMinimize( bSupportsMinimize );
const bool bShowRootWindowImmediately = false;
FSlateApplication::Get().AddWindow( RootWindow, bShowRootWindowImmediately );
FGlobalTabmanager::Get()->SetRootWindow(RootWindow);
FSlateNotificationManager::Get().SetRootWindow(RootWindow);
TSharedPtr<SWidget> MainFrameContent;
bool bLevelEditorIsMainTab = false;
if ( ShouldShowProjectDialogAtStartup() )
{
MainFrameContent = FGameProjectGenerationModule::Get().CreateGameProjectDialog(/*bAllowProjectOpening=*/true, /*bAllowProjectCreate=*/true);
}
else
{
// Get desktop metrics
FDisplayMetrics DisplayMetrics;
FSlateApplication::Get().GetDisplayMetrics( DisplayMetrics );
// Setup a position and size for the main frame window that's centered in the desktop work area
const float CenterScale = 0.65f;
const FVector2D DisplaySize(
DisplayMetrics.PrimaryDisplayWorkAreaRect.Right - DisplayMetrics.PrimaryDisplayWorkAreaRect.Left,
DisplayMetrics.PrimaryDisplayWorkAreaRect.Bottom - DisplayMetrics.PrimaryDisplayWorkAreaRect.Top );
const FVector2D WindowSize = CenterScale * DisplaySize;
TSharedRef<FTabManager::FLayout> LoadedLayout = FLayoutSaveRestore::LoadFromConfig(GEditorLayoutIni,
// We persist the positioning of the level editor and the content browser.
// The asset editors currently do not get saved.
FTabManager::NewLayout( "UnrealEd_Layout_v1.4" )
->AddArea
(
// level editor window
FTabManager::NewPrimaryArea()
->Split
(
FTabManager::NewStack()
->SetSizeCoefficient(2.0f)
->AddTab("LevelEditor", ETabState::OpenedTab)
->AddTab("DockedToolkit", ETabState::ClosedTab)
)
)
->AddArea
(
// content browser window
FTabManager::NewArea(WindowSize)
->Split
(
FTabManager::NewStack()
->SetSizeCoefficient(1.0f)
->AddTab("ContentBrowser1Tab", ETabState::ClosedTab)
)
)
->AddArea
(
// toolkits window
FTabManager::NewArea(WindowSize)
->SetOrientation(Orient_Vertical)
->Split
(
FTabManager::NewStack()
->SetSizeCoefficient(1.0f)
->AddTab("StandaloneToolkit", ETabState::ClosedTab)
)
->Split
(
FTabManager::NewStack()
->SetSizeCoefficient(0.35f)
->AddTab("MergeTool", ETabState::ClosedTab)
)
)
->AddArea
(
// settings window
FTabManager::NewArea(WindowSize)
->Split
(
FTabManager::NewStack()
->SetSizeCoefficient(1.0f)
->AddTab("EditorSettings", ETabState::ClosedTab)
->AddTab("ProjectSettings", ETabState::ClosedTab)
->AddTab("PluginsEditor", ETabState::ClosedTab)
)
)
);
MainFrameContent = FGlobalTabmanager::Get()->RestoreFrom( LoadedLayout, RootWindow, bEmbedTitleAreaContent );
bLevelEditorIsMainTab = true;
}
RootWindow->SetContent(MainFrameContent.ToSharedRef());
TSharedPtr<SDockTab> MainTab;
if ( bLevelEditorIsMainTab )
{
MainTab = FGlobalTabmanager::Get()->InvokeTab( FTabId("LevelEditor") );
// make sure we only allow the message log to be shown when we have a level editor main tab
FMessageLogModule& MessageLogModule = FModuleManager::LoadModuleChecked<FMessageLogModule>(TEXT("MessageLog"));
MessageLogModule.EnableMessageLogDisplay(true);
}
// Initialize the main frame window
MainFrameHandler->OnMainFrameGenerated( MainTab, RootWindow );
// Show the window!
MainFrameHandler->ShowMainFrameWindow( RootWindow, bStartImmersive, bStartPIE );
MRUFavoritesList = new FMainMRUFavoritesList;
MRUFavoritesList->ReadFromINI();
MainFrameCreationFinishedEvent.Broadcast(RootWindow, ShouldShowProjectDialogAtStartup());
}
}
TSharedRef<SWidget> FMainFrameModule::MakeMainMenu( const TSharedPtr<FTabManager>& TabManager, const TSharedRef< FExtender > Extender ) const
{
return FMainMenu::MakeMainMenu( TabManager, Extender );
}
TSharedRef<SWidget> FMainFrameModule::MakeMainTabMenu( const TSharedPtr<FTabManager>& TabManager, const TSharedRef< FExtender > Extender ) const
{
return FMainMenu::MakeMainTabMenu( TabManager, Extender );
}
BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION
TSharedRef<SWidget> FMainFrameModule::MakeDeveloperTools() const
{
struct Local
{
static FText GetFrameRateAsString()
{
// Clamp to avoid huge averages at startup or after hitches
const float AverageFPS = 1.0f / FSlateApplication::Get().GetAverageDeltaTime();
const float ClampedFPS = ( AverageFPS < 0.0f || AverageFPS > 4000.0f ) ? 0.0f : AverageFPS;
static const FNumberFormattingOptions FormatOptions = FNumberFormattingOptions()
.SetMinimumFractionalDigits(1)
.SetMaximumFractionalDigits(1);
return FText::AsNumber( ClampedFPS, &FormatOptions );
}
static FText GetFrameTimeAsString()
{
// Clamp to avoid huge averages at startup or after hitches
const float AverageMS = FSlateApplication::Get().GetAverageDeltaTime() * 1000.0f;
const float ClampedMS = ( AverageMS < 0.0f || AverageMS > 4000.0f ) ? 0.0f : AverageMS;
static const FNumberFormattingOptions FormatOptions = FNumberFormattingOptions()
.SetMinimumFractionalDigits(1)
.SetMaximumFractionalDigits(1);
static const FText FrameTimeFmt = FText::FromString(TEXT("{0} ms"));
return FText::Format( FrameTimeFmt, FText::AsNumber( ClampedMS, &FormatOptions ) );
}
static FText GetMemoryAsString()
{
// Only refresh process memory allocated after every so often, to reduce fixed frame time overhead
static SIZE_T StaticLastTotalAllocated = 0;
static int32 QueriesUntilUpdate = 1;
if( --QueriesUntilUpdate <= 0 )
{
// Query OS for process memory used
FPlatformMemoryStats MemoryStats = FPlatformMemory::GetStats();
StaticLastTotalAllocated = MemoryStats.UsedPhysical;
// Wait 60 queries until we refresh memory again
QueriesUntilUpdate = 60;
}
static const FNumberFormattingOptions FormatOptions = FNumberFormattingOptions()
.SetMinimumFractionalDigits(2)
.SetMaximumFractionalDigits(2);
static const FText MemorySizeFmt = FText::FromString(TEXT("{0} mb"));
return FText::Format( MemorySizeFmt, FText::AsNumber( (float)StaticLastTotalAllocated / ( 1024.0f * 1024.0f ), &FormatOptions ) );
}
static FText GetUObjectCountAsString()
{
return FText::AsNumber(GUObjectArray.GetObjectArrayNumMinusAvailable());
}
static void OpenVideo( FString SourceFilePath )
{
FPlatformProcess::ExploreFolder( *( FPaths::GetPath(SourceFilePath) ) );
}
/** Clicked the SaveVideo button available */
static FReply OnClickSaveVideo()
{
// Default the result to fail it will be set to SNotificationItem::CS_Success if saved ok
SNotificationItem::ECompletionState SaveResultState = SNotificationItem::CS_Fail;
// The string we will use to tell the user the result of the save
FText VideoSaveResultText;
FString HyperLinkText;
// Capture unavailable or inactive error string
ICrashTrackerModule* CrashTracker = FModuleManager::LoadModulePtr<ICrashTrackerModule>("CrashTracker");
if(CrashTracker)
{
FString VideoSaveName;
EWriteUserCaptureVideoError::Type WriteResult = CrashTracker->WriteUserVideoNow( VideoSaveName );
// If this returns None the capture was successful, otherwise report the error
if( WriteResult == EWriteUserCaptureVideoError::None )
{
// Setup the string with the path and name of the file
VideoSaveResultText = LOCTEXT( "VideoSavedAs", "Video capture saved as" );
HyperLinkText = FPaths::ConvertRelativePathToFull(VideoSaveName);
// Flag success
SaveResultState = SNotificationItem::CS_Success;
}
else
{
// Write returned an error - differentiate between directory creation failure and the capture unavailable
if( WriteResult == EWriteUserCaptureVideoError::FailedToCreateDirectory )
{
FFormatNamedArguments Args;
Args.Add( TEXT("VideoCaptureDirectory"), FText::FromString( FPaths::ConvertRelativePathToFull(FPaths::VideoCaptureDir()) ) );
VideoSaveResultText = LOCTEXT( "VideoSavedFailedFailedToCreateDir", "Video capture save failed - Failed to create directory\n{VideoCaptureDirectory}" );
}
else
{
VideoSaveResultText = LOCTEXT( "VideoSavedFailedNotRunning", "Video capture save failed - Capture not active or unavailable" );
}
}
}
else
{
// This shouldn't happen as the button is hidden when there is no crash tracker
VideoSaveResultText = LOCTEXT( "VideoSavedFailedNoTracker", "Video capture failed - CrashTracker inactive" );
}
// Inform the user of the result of the operation
FNotificationInfo Info( VideoSaveResultText );
Info.ExpireDuration = 5.0f;
Info.FadeOutDuration = 0.5f;
Info.bUseSuccessFailIcons = false;
Info.bUseLargeFont = false;
if( HyperLinkText != "" )
{
Info.Hyperlink = FSimpleDelegate::CreateStatic(&Local::OpenVideo, HyperLinkText );
Info.HyperlinkText = FText::FromString( HyperLinkText );
}
TWeakPtr<SNotificationItem> SaveMessagePtr;
SaveMessagePtr = FSlateNotificationManager::Get().AddNotification(Info);
SaveMessagePtr.Pin()->SetCompletionState(SaveResultState);
return FReply::Handled();
}
/** @return Returns true if frame rate and memory should be displayed in the UI */
static EVisibility ShouldShowFrameRateAndMemory()
{
return GetDefault<UEditorPerProjectUserSettings>()->bShowFrameRateAndMemory ? EVisibility::SelfHitTestInvisible : EVisibility::Collapsed;
}
};
const FSuperSearchModule& SuperSearchModule = FModuleManager::LoadModuleChecked< FSuperSearchModule >(TEXT("SuperSearch"));
// We need the output log module in order to instantiate SConsoleInputBox widgets
const FOutputLogModule& OutputLogModule = FModuleManager::LoadModuleChecked< FOutputLogModule >(TEXT("OutputLog"));
const FSlateFontInfo& SmallFixedFont = FEditorStyle::GetFontStyle(TEXT("MainFrame.DebugTools.SmallFont") );
const FSlateFontInfo& NormalFixedFont = FEditorStyle::GetFontStyle(TEXT("MainFrame.DebugTools.NormalFont") );
const FSlateFontInfo& LabelFont = FEditorStyle::GetFontStyle(TEXT("MainFrame.DebugTools.LabelFont") );
TSharedPtr< SWidget > DeveloperTools;
TSharedPtr< SEditableTextBox > ExposedEditableTextBox;
ICrashTrackerModule* CrashTracker = FModuleManager::LoadModulePtr<ICrashTrackerModule>("CrashTracker");
bool bCrashTrackerVideoAvailable = false;
if (CrashTracker)
{
bCrashTrackerVideoAvailable = CrashTracker->IsVideoCaptureAvailable();
}
TSharedRef<SWidget> FrameRateAndMemoryWidget =
SNew( SHorizontalBox )
.Visibility_Static( &Local::ShouldShowFrameRateAndMemory )
// FPS
+SHorizontalBox::Slot()
.AutoWidth()
.Padding( 0.0f, 0.0f, 4.0f, 0.0f )
[
SNew( SHorizontalBox )
.Visibility( GIsDemoMode ? EVisibility::Collapsed : EVisibility::HitTestInvisible )
+SHorizontalBox::Slot()
.AutoWidth()
.VAlign(VAlign_Bottom)
[
SNew( STextBlock )
.Text( LOCTEXT("FrameRateLabel", "FPS: ") )
.Font( LabelFont )
.ColorAndOpacity( FLinearColor( 0.3f, 0.3f, 0.3f ) )
]
+SHorizontalBox::Slot()
.AutoWidth()
.VAlign(VAlign_Bottom)
[
SNew( STextBlock )
.Text_Static( &Local::GetFrameRateAsString )
.Font(NormalFixedFont)
.ColorAndOpacity( FLinearColor( 0.6f, 0.6f, 0.6f ) )
]
+SHorizontalBox::Slot()
.AutoWidth()
.VAlign(VAlign_Bottom)
.Padding( 4.0f, 0.0f, 0.0f, 0.0f )
[
SNew( STextBlock )
.Text( LOCTEXT("FrameRate/FrameTime", "/") )
.Font( SmallFixedFont )
.ColorAndOpacity( FLinearColor( 0.4f, 0.4f, 0.4f ) )
]
+SHorizontalBox::Slot()
.AutoWidth()
.VAlign(VAlign_Bottom)
.Padding( 4.0f, 0.0f, 0.0f, 0.0f )
[
SNew( STextBlock )
.Text_Static( &Local::GetFrameTimeAsString )
.Font( SmallFixedFont )
.ColorAndOpacity( FLinearColor( 0.4f, 0.4f, 0.4f ) )
]
]
// Memory
+SHorizontalBox::Slot()
.AutoWidth()
.Padding( 4.0f, 0.0f, 4.0f, 0.0f )
[
SNew( SHorizontalBox )
.Visibility( GIsDemoMode ? EVisibility::Collapsed : EVisibility::HitTestInvisible )
+SHorizontalBox::Slot()
.AutoWidth()
.VAlign(VAlign_Bottom)
[
SNew( STextBlock )
.Text( LOCTEXT("MemoryLabel", "Mem: ") )
.Font( LabelFont )
.ColorAndOpacity( FLinearColor( 0.3f, 0.3f, 0.3f ) )
]
+SHorizontalBox::Slot()
.AutoWidth()
.VAlign(VAlign_Bottom)
[
SNew( STextBlock )
.Text_Static( &Local::GetMemoryAsString )
.Font(NormalFixedFont)
.ColorAndOpacity( FLinearColor( 0.6f, 0.6f, 0.6f ) )
]
]
// UObject count
+SHorizontalBox::Slot()
.AutoWidth()
.Padding( 4.0f, 0.0f, 4.0f, 0.0f )
[
SNew( SHorizontalBox )
.Visibility( GIsDemoMode ? EVisibility::Collapsed : EVisibility::HitTestInvisible )
+SHorizontalBox::Slot()
.AutoWidth()
.VAlign(VAlign_Bottom)
[
SNew( STextBlock )
.Text( LOCTEXT("UObjectCountLabel", "Objs: ") )
.Font( LabelFont )
.ColorAndOpacity( FLinearColor( 0.3f, 0.3f, 0.3f ) )
]
+SHorizontalBox::Slot()
.AutoWidth()
.VAlign(VAlign_Bottom)
[
SNew( STextBlock )
.Text_Static( &Local::GetUObjectCountAsString )
.Font(NormalFixedFont)
.ColorAndOpacity( FLinearColor( 0.6f, 0.6f, 0.6f ) )
]
]
;
bool bUseSuperSearch = true;
// Invisible border, so that we can animate our box panel size
return SNew( SBorder )
.Visibility( EVisibility::SelfHitTestInvisible )
.Padding( FMargin(0.0f, 0.0f, 0.0f, 1.0f) )
.VAlign(VAlign_Bottom)
.BorderImage( FEditorStyle::GetBrush("NoBorder") )
[
SNew( SHorizontalBox )
.Visibility( EVisibility::SelfHitTestInvisible )
+SHorizontalBox::Slot()
.AutoWidth()
.Padding( 0.0f )
[
FrameRateAndMemoryWidget
]
+SHorizontalBox::Slot()
.AutoWidth()
.VAlign(VAlign_Bottom)
.Padding( 0.0f )
[
SNew(SBox)
.Padding( FMargin( 4.0f, 0.0f, 0.0f, 0.0f ) )
[
bUseSuperSearch ? SuperSearchModule.MakeSearchBox( ExposedEditableTextBox ) : OutputLogModule.MakeConsoleInputBox( ExposedEditableTextBox )
]
]
// Editor live streaming toggle button
+SHorizontalBox::Slot()
.AutoWidth()
.VAlign( VAlign_Bottom )
[
SNew(SButton)
.Visibility_Static( []() -> EVisibility { return IEditorLiveStreaming::Get().IsLiveStreamingAvailable() ? EVisibility::Visible : EVisibility::Collapsed; } )
.ToolTipText( LOCTEXT( "BroadcastTooltip", "Starts or stops broadcasting of this editor session to a live internet streaming service." ) )
.OnClicked_Static( []
{
// Toggle broadcasting on or off
if( IEditorLiveStreaming::Get().IsBroadcastingEditor() )
{
IEditorLiveStreaming::Get().StopBroadcastingEditor();
}
else
{
IEditorLiveStreaming::Get().StartBroadcastingEditor();
}
return FReply::Handled();
} )
.ButtonStyle( FEditorStyle::Get(), "NoBorder" )
.ContentPadding(FMargin(1,0))
[
SNew(SImage)
.Image( FEditorStyle::GetBrush("EditorLiveStreaming.BroadcastButton") )
.ColorAndOpacity_Static( []
{
// Pulsate the button graphics while we're broadcasting
FSlateColor Color( FLinearColor::White );
if( IEditorLiveStreaming::Get().IsBroadcastingEditor() )
{
Color = FLinearColor( 1.0f, 1.0f, 1.0f, FMath::MakePulsatingValue( FSlateApplication::Get().GetCurrentTime(), 2.0f ) );
}
return Color;
} )
]
]
// Crash report "save video" button
+SHorizontalBox::Slot()
.AutoWidth()
.VAlign( VAlign_Bottom )
[
SNew(SButton)
.Visibility( bCrashTrackerVideoAvailable ? EVisibility::Visible : EVisibility::Collapsed )
.ToolTipText( LOCTEXT( "SaveReplayTooltip", "Saves a video of the last 20 seconds of your work." ) )
.OnClicked_Static( &Local::OnClickSaveVideo )
.ButtonStyle( FEditorStyle::Get(), "NoBorder" )
.ContentPadding(FMargin(1,0))
[
SNew(SImage)
. Image( FEditorStyle::GetBrush("CrashTracker.Record") )
]
]
];
}
END_SLATE_FUNCTION_BUILD_OPTIMIZATION
void FMainFrameModule::SetLevelNameForWindowTitle( const FString& InLevelFileName )
{
LoadedLevelName = (InLevelFileName.Len() > 0)
? FPaths::GetBaseFilename(InLevelFileName)
: NSLOCTEXT("UnrealEd", "Untitled", "Untitled" ).ToString();
}
/* IModuleInterface implementation
*****************************************************************************/
void FMainFrameModule::StartupModule( )
{
MRUFavoritesList = NULL;
ensureMsgf(!IsRunningGame(), TEXT("The MainFrame module should only be loaded when running the editor. Code that extends the editor, adds menu items, etc... should not run when running in -game mode or in a non-WITH_EDITOR build"));
MainFrameHandler = MakeShareable(new FMainFrameHandler);
FGenericCommands::Register();
FMainFrameCommands::Register();
SetLevelNameForWindowTitle(TEXT(""));
// Register to find out about when hot reload completes, so we can show a notification
IHotReloadModule& HotReloadModule = IHotReloadModule::Get();
HotReloadModule.OnModuleCompilerStarted().AddRaw( this, &FMainFrameModule::HandleLevelEditorModuleCompileStarted );
HotReloadModule.OnModuleCompilerFinished().AddRaw( this, &FMainFrameModule::HandleLevelEditorModuleCompileFinished );
HotReloadModule.OnHotReload().AddRaw( this, &FMainFrameModule::HandleHotReloadFinished );
#if WITH_EDITOR
ISourceCodeAccessModule& SourceCodeAccessModule = FModuleManager::LoadModuleChecked<ISourceCodeAccessModule>("SourceCodeAccess");
SourceCodeAccessModule.OnLaunchingCodeAccessor().AddRaw( this, &FMainFrameModule::HandleCodeAccessorLaunching );
SourceCodeAccessModule.OnDoneLaunchingCodeAccessor().AddRaw( this, &FMainFrameModule::HandleCodeAccessorLaunched );
SourceCodeAccessModule.OnOpenFileFailed().AddRaw( this, &FMainFrameModule::HandleCodeAccessorOpenFileFailed );
#endif
// load sounds
CompileStartSound = LoadObject<USoundBase>(NULL, TEXT("/Engine/EditorSounds/Notifications/CompileStart_Cue.CompileStart_Cue"));
CompileStartSound->AddToRoot();
CompileSuccessSound = LoadObject<USoundBase>(NULL, TEXT("/Engine/EditorSounds/Notifications/CompileSuccess_Cue.CompileSuccess_Cue"));
CompileSuccessSound->AddToRoot();
CompileFailSound = LoadObject<USoundBase>(NULL, TEXT("/Engine/EditorSounds/Notifications/CompileFailed_Cue.CompileFailed_Cue"));
CompileFailSound->AddToRoot();
ModuleCompileStartTime = 0.0f;
// migrate old layout settings
FLayoutSaveRestore::MigrateConfig(GEditorPerProjectIni, GEditorLayoutIni);
}
void FMainFrameModule::ShutdownModule( )
{
// Destroy the main frame window
TSharedPtr< SWindow > ParentWindow( GetParentWindow() );
if( ParentWindow.IsValid() )
{
ParentWindow->DestroyWindowImmediately();
}
MainFrameHandler.Reset();
FMainFrameCommands::Unregister();
if( IHotReloadModule::IsAvailable() )
{
IHotReloadModule& HotReloadModule = IHotReloadModule::Get();
HotReloadModule.OnHotReload().RemoveAll( this );
HotReloadModule.OnModuleCompilerStarted().RemoveAll( this );
HotReloadModule.OnModuleCompilerFinished().RemoveAll( this );
}
#if WITH_EDITOR
if(FModuleManager::Get().IsModuleLoaded("SourceCodeAccess"))
{
ISourceCodeAccessModule& SourceCodeAccessModule = FModuleManager::GetModuleChecked<ISourceCodeAccessModule>("SourceCodeAccess");
SourceCodeAccessModule.OnLaunchingCodeAccessor().RemoveAll( this );
SourceCodeAccessModule.OnDoneLaunchingCodeAccessor().RemoveAll( this );
SourceCodeAccessModule.OnOpenFileFailed().RemoveAll( this );
}
#endif
if(CompileStartSound != NULL)
{
if (!GExitPurge)
{
CompileStartSound->RemoveFromRoot();
}
CompileStartSound = NULL;
}
if(CompileSuccessSound != NULL)
{
if (!GExitPurge)
{
CompileSuccessSound->RemoveFromRoot();
}
CompileSuccessSound = NULL;
}
if(CompileFailSound != NULL)
{
if (!GExitPurge)
{
CompileFailSound->RemoveFromRoot();
}
CompileFailSound = NULL;
}
}
/* FMainFrameModule implementation
*****************************************************************************/
bool FMainFrameModule::ShouldShowProjectDialogAtStartup( ) const
{
return !FApp::HasGameName();
}
/* FMainFrameModule event handlers
*****************************************************************************/
void FMainFrameModule::HandleLevelEditorModuleCompileStarted( bool bIsAsyncCompile )
{
ModuleCompileStartTime = FPlatformTime::Seconds();
if (CompileNotificationPtr.IsValid())
{
CompileNotificationPtr.Pin()->ExpireAndFadeout();
}
if ( GEditor )
{
GEditor->PlayEditorSound(CompileStartSound);
}
FNotificationInfo Info( NSLOCTEXT("MainFrame", "RecompileInProgress", "Compiling C++ Code") );
Info.Image = FEditorStyle::GetBrush(TEXT("LevelEditor.RecompileGameCode"));
Info.ExpireDuration = 5.0f;
Info.bFireAndForget = false;
// We can only show the cancel button on async builds
if (bIsAsyncCompile)
{
Info.ButtonDetails.Add(FNotificationButtonInfo(LOCTEXT("CancelC++Compilation", "Cancel"), FText(), FSimpleDelegate::CreateRaw(this, &FMainFrameModule::OnCancelCodeCompilationClicked)));
}
CompileNotificationPtr = FSlateNotificationManager::Get().AddNotification(Info);
if (CompileNotificationPtr.IsValid())
{
CompileNotificationPtr.Pin()->SetCompletionState(SNotificationItem::CS_Pending);
}
}
void FMainFrameModule::OnCancelCodeCompilationClicked()
{
IHotReloadModule::Get().RequestStopCompilation();
}
void FMainFrameModule::HandleLevelEditorModuleCompileFinished(const FString& LogDump, ECompilationResult::Type CompilationResult, bool bShowLog)
{
// Track stats
{
const float ModuleCompileDuration = (float)(FPlatformTime::Seconds() - ModuleCompileStartTime);
UE_LOG(LogMainFrame, Log, TEXT("MainFrame: Module compiling took %.3f seconds"), ModuleCompileDuration);
if( FEngineAnalytics::IsAvailable() )
{
TArray< FAnalyticsEventAttribute > CompileAttribs;
CompileAttribs.Add(FAnalyticsEventAttribute(TEXT("Duration"), FString::Printf(TEXT("%.3f"), ModuleCompileDuration)));
CompileAttribs.Add(FAnalyticsEventAttribute(TEXT("Result"), ECompilationResult::ToString(CompilationResult)));
FEngineAnalytics::GetProvider().RecordEvent(TEXT("Editor.Modules.Recompile"), CompileAttribs);
}
}
TSharedPtr<SNotificationItem> NotificationItem = CompileNotificationPtr.Pin();
if (NotificationItem.IsValid())
{
if (!ECompilationResult::Failed(CompilationResult))
{
if ( GEditor )
{
GEditor->PlayEditorSound(CompileSuccessSound);
}
NotificationItem->SetText(NSLOCTEXT("MainFrame", "RecompileComplete", "Compile Complete!"));
NotificationItem->SetExpireDuration( 5.0f );
NotificationItem->SetCompletionState(SNotificationItem::CS_Success);
}
else
{
struct Local
{
static void ShowCompileLog()
{
FMessageLogModule& MessageLogModule = FModuleManager::GetModuleChecked<FMessageLogModule>("MessageLog");
MessageLogModule.OpenMessageLog(FCompilerResultsLog::GetLogName());
}
};
if ( GEditor )
{
GEditor->PlayEditorSound(CompileFailSound);
}
if (CompilationResult == ECompilationResult::FailedDueToHeaderChange)
{
NotificationItem->SetText(NSLOCTEXT("MainFrame", "RecompileFailedDueToHeaderChange", "Compile failed due to the header changes. Close the editor and recompile project in IDE to apply changes."));
}
else if (CompilationResult == ECompilationResult::Canceled)
{
NotificationItem->SetText(NSLOCTEXT("MainFrame", "RecompileCanceled", "Compile Canceled!"));
}
else
{
NotificationItem->SetText(NSLOCTEXT("MainFrame", "RecompileFailed", "Compile Failed!"));
}
NotificationItem->SetCompletionState(SNotificationItem::CS_Fail);
NotificationItem->SetHyperlink(FSimpleDelegate::CreateStatic(&Local::ShowCompileLog));
NotificationItem->SetExpireDuration(30.0f);
}
NotificationItem->ExpireAndFadeout();
CompileNotificationPtr.Reset();
}
}
void FMainFrameModule::HandleHotReloadFinished( bool bWasTriggeredAutomatically )
{
// Only play the notification for hot reloads that were triggered automatically. If the user triggered the hot reload, they'll
// have a different visual cue for that, such as the "Compiling Complete!" notification
if( bWasTriggeredAutomatically )
{
FNotificationInfo Info( LOCTEXT("HotReloadFinished", "Hot Reload Complete!") );
Info.Image = FEditorStyle::GetBrush(TEXT("LevelEditor.RecompileGameCode"));
Info.FadeInDuration = 0.1f;
Info.FadeOutDuration = 0.5f;
Info.ExpireDuration = 1.5f;
Info.bUseThrobber = false;
Info.bUseSuccessFailIcons = true;
Info.bUseLargeFont = true;
Info.bFireAndForget = false;
Info.bAllowThrottleWhenFrameRateIsLow = false;
auto NotificationItem = FSlateNotificationManager::Get().AddNotification( Info );
NotificationItem->SetCompletionState(SNotificationItem::CS_Success);
NotificationItem->ExpireAndFadeout();
GEditor->PlayEditorSound(CompileSuccessSound);
}
}
void FMainFrameModule::HandleCodeAccessorLaunched( const bool WasSuccessful )
{
TSharedPtr<SNotificationItem> NotificationItem = CodeAccessorNotificationPtr.Pin();
if (NotificationItem.IsValid())
{
ISourceCodeAccessModule& SourceCodeAccessModule = FModuleManager::LoadModuleChecked<ISourceCodeAccessModule>("SourceCodeAccess");
const FText AccessorNameText = SourceCodeAccessModule.GetAccessor().GetNameText();
if (WasSuccessful)
{
NotificationItem->SetText( FText::Format(LOCTEXT("CodeAccessorLoadComplete", "{0} loaded!"), AccessorNameText) );
NotificationItem->SetCompletionState(SNotificationItem::CS_Success);
}
else
{
NotificationItem->SetText( FText::Format(LOCTEXT("CodeAccessorLoadFailed", "{0} failed to launch!"), AccessorNameText) );
NotificationItem->SetCompletionState(SNotificationItem::CS_Fail);
}
NotificationItem->ExpireAndFadeout();
CodeAccessorNotificationPtr.Reset();
}
}
void FMainFrameModule::HandleCodeAccessorLaunching( )
{
if (CodeAccessorNotificationPtr.IsValid())
{
CodeAccessorNotificationPtr.Pin()->ExpireAndFadeout();
}
ISourceCodeAccessModule& SourceCodeAccessModule = FModuleManager::LoadModuleChecked<ISourceCodeAccessModule>("SourceCodeAccess");
const FText AccessorNameText = SourceCodeAccessModule.GetAccessor().GetNameText();
FNotificationInfo Info( FText::Format(LOCTEXT("CodeAccessorLoadInProgress", "Loading {0}"), AccessorNameText) );
Info.bFireAndForget = false;
CodeAccessorNotificationPtr = FSlateNotificationManager::Get().AddNotification(Info);
CodeAccessorNotificationPtr.Pin()->SetCompletionState(SNotificationItem::CS_Pending);
}
void FMainFrameModule::HandleCodeAccessorOpenFileFailed(const FString& Filename)
{
auto* Info = new FNotificationInfo(FText::Format(LOCTEXT("FileNotFound", "Could not find code file ({Filename})"), FText::FromString(Filename)));
Info->ExpireDuration = 3.0f;
FSlateNotificationManager::Get().QueueNotification(Info);
}
#undef LOCTEXT_NAMESPACE
IMPLEMENT_MODULE(FMainFrameModule, MainFrame);