Files
UnrealEngineUWP/Engine/Source/Editor/IntroTutorials/Private/STutorialOverlay.cpp

306 lines
11 KiB
C++
Raw Normal View History

// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved.
#include "IntroTutorialsPrivatePCH.h"
#include "STutorialOverlay.h"
#include "STutorialContent.h"
#include "EditorTutorial.h"
#include "IntroTutorials.h"
#include "Kismet2/KismetEditorUtilities.h"
#include "LevelEditor.h"
#include "BlueprintEditorUtils.h"
#include "Guid.h"
#include "BlueprintEditor.h"
static FName IntroTutorialsModuleName("IntroTutorials");
void STutorialOverlay::Construct(const FArguments& InArgs, UEditorTutorial* InTutorial, FTutorialStage* const InStage)
{
ParentWindow = InArgs._ParentWindow;
bIsStandalone = InArgs._IsStandalone;
OnClosed = InArgs._OnClosed;
bHasValidContent = InStage != nullptr;
OnWidgetWasDrawn = InArgs._OnWidgetWasDrawn;
TSharedPtr<SOverlay> Overlay;
ChildSlot
[
SAssignNew(Overlay, SOverlay)
+SOverlay::Slot()
[
SAssignNew(OverlayCanvas, SCanvas)
]
];
if(InStage != nullptr)
{
// add non-widget content, if any
if(InArgs._AllowNonWidgetContent && InStage->Content.Type != ETutorialContent::None)
{
Overlay->AddSlot()
[
SNew(SHorizontalBox)
+SHorizontalBox::Slot()
.VAlign(VAlign_Center)
.HAlign(HAlign_Center)
[
SNew(STutorialContent, InTutorial, InStage->Content)
.OnClosed(InArgs._OnClosed)
.OnNextClicked(InArgs._OnNextClicked)
.OnHomeClicked(InArgs._OnHomeClicked)
.OnBackClicked(InArgs._OnBackClicked)
.IsBackEnabled(InArgs._IsBackEnabled)
.IsHomeEnabled(InArgs._IsHomeEnabled)
.IsNextEnabled(InArgs._IsNextEnabled)
.IsStandalone(InArgs._IsStandalone)
.WrapTextAt(600.0f)
.NextButtonText(InStage->NextButtonText)
.BackButtonText(InStage->BackButtonText)
]
];
}
if(InStage->WidgetContent.Num() > 0)
{
FIntroTutorials& IntroTutorials = FModuleManager::Get().GetModuleChecked<FIntroTutorials>("IntroTutorials");
// now add canvas slots for widget-bound content
for (const FTutorialWidgetContent& WidgetContent : InStage->WidgetContent)
{
if (WidgetContent.Content.Type != ETutorialContent::None)
{
TSharedPtr<STutorialContent> ContentWidget =
SNew(STutorialContent, InTutorial, WidgetContent.Content)
.HAlign(WidgetContent.HorizontalAlignment)
.VAlign(WidgetContent.VerticalAlignment)
.Offset(WidgetContent.Offset)
.IsStandalone(bIsStandalone)
.OnClosed(InArgs._OnClosed)
.OnNextClicked(InArgs._OnNextClicked)
.OnHomeClicked(InArgs._OnHomeClicked)
.OnBackClicked(InArgs._OnBackClicked)
.IsBackEnabled(InArgs._IsBackEnabled)
.IsHomeEnabled(InArgs._IsHomeEnabled)
.IsNextEnabled(InArgs._IsNextEnabled)
.WrapTextAt(WidgetContent.ContentWidth)
.Anchor(WidgetContent.WidgetAnchor)
.AllowNonWidgetContent(InArgs._AllowNonWidgetContent)
.OnWasWidgetDrawn(InArgs._OnWasWidgetDrawn);
PerformWidgetInteractions(InTutorial, WidgetContent);
OverlayCanvas->AddSlot()
.Position(TAttribute<FVector2D>::Create(TAttribute<FVector2D>::FGetter::CreateSP(ContentWidget.Get(), &STutorialContent::GetPosition)))
.Size(TAttribute<FVector2D>::Create(TAttribute<FVector2D>::FGetter::CreateSP(ContentWidget.Get(), &STutorialContent::GetSize)))
[
ContentWidget.ToSharedRef()
];
OnPaintNamedWidget.AddSP(ContentWidget.Get(), &STutorialContent::HandlePaintNamedWidget);
OnResetNamedWidget.AddSP(ContentWidget.Get(), &STutorialContent::HandleResetNamedWidget);
OnCacheWindowSize.AddSP(ContentWidget.Get(), &STutorialContent::HandleCacheWindowSize);
}
}
}
}
}
int32 STutorialOverlay::OnPaint( const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyClippingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled ) const
{
if(ParentWindow.IsValid())
{
bool bIsPicking = false;
FName WidgetNameToHighlight = NAME_None;
FIntroTutorials& IntroTutorials = FModuleManager::Get().GetModuleChecked<FIntroTutorials>(IntroTutorialsModuleName);
if(IntroTutorials.OnIsPicking().IsBound())
{
bIsPicking = IntroTutorials.OnIsPicking().Execute(WidgetNameToHighlight);
}
if(bIsPicking || bHasValidContent)
{
TSharedPtr<SWindow> PinnedWindow = ParentWindow.Pin();
OnResetNamedWidget.Broadcast();
OnCacheWindowSize.Broadcast(PinnedWindow->GetWindowGeometryInWindow().Size);
LayerId = TraverseWidgets(PinnedWindow.ToSharedRef(), PinnedWindow->GetWindowGeometryInWindow(), MyClippingRect, OutDrawElements, LayerId);
}
}
return SCompoundWidget::OnPaint(Args, AllottedGeometry, MyClippingRect, OutDrawElements, LayerId, InWidgetStyle, bParentEnabled);
}
int32 STutorialOverlay::TraverseWidgets(TSharedRef<SWidget> InWidget, const FGeometry& InGeometry, const FSlateRect& MyClippingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId) const
{
bool bIsPicking = false;
bool bShouldHighlight = false;
bool bShouldDraw = false;
FName WidgetNameToHighlight = NAME_None;
FIntroTutorials& IntroTutorials = FModuleManager::Get().GetModuleChecked<FIntroTutorials>(IntroTutorialsModuleName);
if (IntroTutorials.OnValidatePickingCandidate().IsBound())
{
bIsPicking = IntroTutorials.OnValidatePickingCandidate().Execute(InWidget,WidgetNameToHighlight,bShouldHighlight);
}
// First draw the widget if we should
Copying //UE4/Dev-Framework to //UE4/Dev-Main (Source: //UE4/Dev-Framework @ 2972815) #lockdown Nick.Penwarden ========================== MAJOR FEATURES + CHANGES ========================== Change 2821607 on 2016/01/08 by Mieszko.Zielinski Added a way to limit amount of information logged by vlog by discarding logs from classes from outside of class whitelist #UE4 This feature was followed by refactoring of functions taking FVisualLogEntry pointers to use references instead. Change 2828384 on 2016/01/14 by Mieszko.Zielinski Back out of visual log refactor done as part of CL#2821607 #UE4 Change 2965743 on 2016/05/04 by Tom.Looman Added check to PostActorConstruction to avoid BeginPlay call on pendingkill actor. UE-27528 #rb MarcA Change 2965744 on 2016/05/04 by Marc.Audy VS2015 Shadow Variable fixes Change 2965813 on 2016/05/04 by Tom.Looman Moved UninitializeComponents outside (bActorInitialized) to always uninit components when actors gets destroyed early. UE-27529 #rb MarcA Change 2966564 on 2016/05/04 by Marc.Audy VS2015 shadow variable fixes Change 2967244 on 2016/05/05 by Jon.Nabozny Remove UPROPERTY from members that don't require serialization and aren't user editable. #JIRA UE-30155 Change 2967377 on 2016/05/05 by Lukasz.Furman fixed processing of AIMessages when new message appears during notify loop #ue4 Change 2967437 on 2016/05/05 by Marc.Audy Add a static One to TBigInt Remove numerous local statics and TEncryptionInt specific version in KeyGenerator.cpp Part of fixing shadow variables for VS2015 Change 2967465 on 2016/05/05 by Marc.Audy Fix VS2015 shadow variables fixes Change 2967552 on 2016/05/05 by Marc.Audy Fix compile error in DocumentationCode Change 2967556 on 2016/05/05 by Marc.Audy Enable shadow variable warnings in 2015 Change 2967836 on 2016/05/05 by Marc.Audy Another DocumentationCode project fix Change 2967941 on 2016/05/05 by Marc.Audy Make bShowHUD not config Expose HUD properties to blueprints Cleanup stale entries in BaseGame.ini Deprecate unnecessary colors in AHUD in favor of using FColor statics #jira UE-30045 Change 2969008 on 2016/05/06 by Marc.Audy VS2015 Shadow Variable fixes found by CIS Change 2969315 on 2016/05/06 by John.Abercrombie Duplicating CL 2969279 from //Fortnite/Main/ Behavior tree auxilary nodes, parallel tasks, active tasks, and aborting tasks shouldn't be ticked while the behavior tree is paused -------- Integrated using branch //Fortnite/Main/_to_//UE4/Dev-Framework of change#2969279 by John.Abercrombie on 2016/05/06 14:21:40. Change 2969611 on 2016/05/06 by Marc.Audy Default bShowHUD to true Change 2971041 on 2016/05/09 by Marc.Audy Add Get/Set Actor/Component TickInterval functions and expose to blueprints Change 2971072 on 2016/05/09 by Marc.Audy Fix VS2015 shadow variables warnings Change 2971629 on 2016/05/09 by Marc.Audy PR#1981 (contributed by EverNewJoy) CheatManager is blueprintable (though very basic exposure at this time) and can be set from PlayerController DebugCameraController is now visible and can be subclassed and specified via CheatManager blueprint #jira UE-25901 Change 2971632 on 2016/05/09 by Marc.Audy Missed file from CL# 2971629 [CL 2972828 by Marc Audy in Main branch]
2016-05-10 16:00:39 -04:00
TSharedPtr<FTagMetaData> WidgetMetaData = InWidget->GetMetaData<FTagMetaData>();
const FName WidgetTag = (WidgetMetaData.IsValid() && WidgetMetaData->Tag.IsValid()) ? WidgetMetaData->Tag : InWidget->GetTag();
if (WidgetTag != NAME_None || WidgetMetaData.IsValid())
{
// we are a named widget - ask it to draw
OnPaintNamedWidget.Broadcast(InWidget, InGeometry);
Copying //UE4/Dev-Framework to //UE4/Dev-Main (Source: //UE4/Dev-Framework @ 2972815) #lockdown Nick.Penwarden ========================== MAJOR FEATURES + CHANGES ========================== Change 2821607 on 2016/01/08 by Mieszko.Zielinski Added a way to limit amount of information logged by vlog by discarding logs from classes from outside of class whitelist #UE4 This feature was followed by refactoring of functions taking FVisualLogEntry pointers to use references instead. Change 2828384 on 2016/01/14 by Mieszko.Zielinski Back out of visual log refactor done as part of CL#2821607 #UE4 Change 2965743 on 2016/05/04 by Tom.Looman Added check to PostActorConstruction to avoid BeginPlay call on pendingkill actor. UE-27528 #rb MarcA Change 2965744 on 2016/05/04 by Marc.Audy VS2015 Shadow Variable fixes Change 2965813 on 2016/05/04 by Tom.Looman Moved UninitializeComponents outside (bActorInitialized) to always uninit components when actors gets destroyed early. UE-27529 #rb MarcA Change 2966564 on 2016/05/04 by Marc.Audy VS2015 shadow variable fixes Change 2967244 on 2016/05/05 by Jon.Nabozny Remove UPROPERTY from members that don't require serialization and aren't user editable. #JIRA UE-30155 Change 2967377 on 2016/05/05 by Lukasz.Furman fixed processing of AIMessages when new message appears during notify loop #ue4 Change 2967437 on 2016/05/05 by Marc.Audy Add a static One to TBigInt Remove numerous local statics and TEncryptionInt specific version in KeyGenerator.cpp Part of fixing shadow variables for VS2015 Change 2967465 on 2016/05/05 by Marc.Audy Fix VS2015 shadow variables fixes Change 2967552 on 2016/05/05 by Marc.Audy Fix compile error in DocumentationCode Change 2967556 on 2016/05/05 by Marc.Audy Enable shadow variable warnings in 2015 Change 2967836 on 2016/05/05 by Marc.Audy Another DocumentationCode project fix Change 2967941 on 2016/05/05 by Marc.Audy Make bShowHUD not config Expose HUD properties to blueprints Cleanup stale entries in BaseGame.ini Deprecate unnecessary colors in AHUD in favor of using FColor statics #jira UE-30045 Change 2969008 on 2016/05/06 by Marc.Audy VS2015 Shadow Variable fixes found by CIS Change 2969315 on 2016/05/06 by John.Abercrombie Duplicating CL 2969279 from //Fortnite/Main/ Behavior tree auxilary nodes, parallel tasks, active tasks, and aborting tasks shouldn't be ticked while the behavior tree is paused -------- Integrated using branch //Fortnite/Main/_to_//UE4/Dev-Framework of change#2969279 by John.Abercrombie on 2016/05/06 14:21:40. Change 2969611 on 2016/05/06 by Marc.Audy Default bShowHUD to true Change 2971041 on 2016/05/09 by Marc.Audy Add Get/Set Actor/Component TickInterval functions and expose to blueprints Change 2971072 on 2016/05/09 by Marc.Audy Fix VS2015 shadow variables warnings Change 2971629 on 2016/05/09 by Marc.Audy PR#1981 (contributed by EverNewJoy) CheatManager is blueprintable (though very basic exposure at this time) and can be set from PlayerController DebugCameraController is now visible and can be subclassed and specified via CheatManager blueprint #jira UE-25901 Change 2971632 on 2016/05/09 by Marc.Audy Missed file from CL# 2971629 [CL 2972828 by Marc Audy in Main branch]
2016-05-10 16:00:39 -04:00
OnWidgetWasDrawn.ExecuteIfBound(WidgetTag);
}
// Next check and draw the highlight as appropriate
if (bIsPicking == true)
{
// if we are picking, we need to draw an outline here
if(WidgetNameToHighlight != NAME_None )
{
if(bIsPicking == true)
{
const FLinearColor Color = bIsPicking && bShouldHighlight ? FLinearColor::Green : FLinearColor::White;
FSlateDrawElement::MakeBox(OutDrawElements, LayerId++, InGeometry.ToPaintGeometry(), FCoreStyle::Get().GetBrush(TEXT("Debug.Border")), MyClippingRect, ESlateDrawEffect::None, Color);
}
}
}
FArrangedChildren ArrangedChildren(EVisibility::Visible);
InWidget->ArrangeChildren(InGeometry, ArrangedChildren);
for(int32 ChildIndex = 0; ChildIndex < ArrangedChildren.Num(); ChildIndex++)
{
const FArrangedWidget& ArrangedWidget = ArrangedChildren[ChildIndex];
LayerId = TraverseWidgets(ArrangedWidget.Widget, ArrangedWidget.Geometry, MyClippingRect, OutDrawElements, LayerId);
}
return LayerId;
}
void STutorialOverlay::PerformWidgetInteractions(UEditorTutorial* InTutorial, const FTutorialWidgetContent &WidgetContent)
{
// Open any browser we need too
OpenBrowserForWidgetAnchor(InTutorial, WidgetContent);
FocusOnAnyBlueprintNodes(WidgetContent);
}
void STutorialOverlay::OpenBrowserForWidgetAnchor(UEditorTutorial* InTutorial, const FTutorialWidgetContent &WidgetContent)
{
if(!WidgetContent.WidgetAnchor.TabToFocusOrOpen.IsEmpty())
{
IAssetEditorInstance* AssetEditor = nullptr;
// Check to see if we can find a blueprint relevant to this node and open the editor for that (Then try to get the tabmanager from that)
if(WidgetContent.WidgetAnchor.OuterName.Len() > 0)
{
// Remove the prefix from the name
int32 Space = WidgetContent.WidgetAnchor.OuterName.Find(TEXT(" "));
FString Name = WidgetContent.WidgetAnchor.OuterName.RightChop(Space + 1);
TArray<FString> AssetPaths;
AssetPaths.Add(Name);
FAssetEditorManager::Get().OpenEditorsForAssets(AssetPaths);
UObject* Blueprint = FindObject<UObject>(ANY_PACKAGE, *Name);
// If we found a blueprint
if(Blueprint != nullptr)
{
IAssetEditorInstance* PotentialAssetEditor = FAssetEditorManager::Get().FindEditorForAsset(Blueprint, false);
if(PotentialAssetEditor != nullptr)
{
AssetEditor = PotentialAssetEditor;
}
}
}
// If we haven't found a tab manager, next check the asset editor that we reference in this tutorial, if any
if(AssetEditor == nullptr)
{
// Try looking for the object that this tutorial references (it should already be loaded by this tutorial if it exists).
UObject* AssetObject = InTutorial->AssetToUse.ResolveObject();
if(AssetObject != nullptr)
{
IAssetEditorInstance* PotentialAssetEditor = FAssetEditorManager::Get().FindEditorForAsset(AssetObject, false);
if(PotentialAssetEditor != nullptr)
{
AssetEditor = PotentialAssetEditor;
}
}
}
// Invoke any tab
if(AssetEditor != nullptr)
{
AssetEditor->InvokeTab(FTabId(*WidgetContent.WidgetAnchor.TabToFocusOrOpen));
}
else
{
// fallback to trying the main level editor tab manager
FLevelEditorModule& LevelEditorModule = FModuleManager::GetModuleChecked<FLevelEditorModule>(TEXT("LevelEditor"));
TSharedPtr<FTabManager> LevelEditorTabManager = LevelEditorModule.GetLevelEditorTabManager();
LevelEditorTabManager->InvokeTab(FName(*WidgetContent.WidgetAnchor.TabToFocusOrOpen));
}
}
}
void STutorialOverlay::FocusOnAnyBlueprintNodes(const FTutorialWidgetContent &WidgetContent)
{
if (WidgetContent.bAutoFocus == false)
{
return;
}
const FString Name = WidgetContent.WidgetAnchor.OuterName;
const FName ObjectPath = WidgetContent.WidgetAnchor.WrapperIdentifier;
int32 NameIndex;
Name.FindLastChar(TEXT('.'), NameIndex);
FString BlueprintName = Name.RightChop(NameIndex + 1);
UBlueprint* Blueprint = FindObject<UBlueprint>(ANY_PACKAGE, *BlueprintName);
// If we find a blueprint
if (Blueprint != nullptr)
{
// Try to grab guid
FGuid NodeGuid;
FGuid::Parse(WidgetContent.WidgetAnchor.GUIDString, NodeGuid);
UEdGraphNode* OutNode = NULL;
if (UEdGraphNode* GraphNode = FBlueprintEditorUtils::GetNodeByGUID(Blueprint, NodeGuid))
{
FKismetEditorUtilities::BringKismetToFocusAttentionOnObject(GraphNode, false);
}
}
else if ( !ObjectPath.IsNone() )
{
// if we didn't have a blueprint object to focus on, try it with a regular one
UObject* FocusObject = FindObject<UObject>(ANY_PACKAGE, *ObjectPath.ToString());
// If we didn't find it, maybe it just hasn't been loaded yet
if( FocusObject == nullptr )
{
FocusObject = LoadObject<UObject>(nullptr, *ObjectPath.ToString(),nullptr, LOAD_FindIfFail);
}
// If we found an asset redirector, we need to follow it
UObjectRedirector* Redir = dynamic_cast<UObjectRedirector*>(FocusObject);
if (Redir)
{
FocusObject = Redir->DestinationObject;
}
// If we failed to find the object, it may be a class that has been redirected
if (!FocusObject)
{
const FString ObjectName = FPackageName::ObjectPathToObjectName(ObjectPath.ToString());
Merging UE4-Streaming to UE4 - Linkers are no longer UObjects. Renamed ULinker, ULinkerLoad and ULinkerSave to FLinker, FLinkerLoad, FLinkerSave respectively - Linkers are now associated with their UPackages - Linker version is now stored in UPackages - Async loading is now performed on a separate thread (if platform supports it and only in cooked builds), with the exception of PostLoad which is still done on the game thread - Added UObject::IsPostLoadThreadSafe() function to determine if PostLoad is thread safe and can be executed on the async loading thread (defaults to false) - UObject creation is now thread safe and can be performed on any thread - Move many of the linker/UObject globals into FUObjectThreadContext (TLS) - GetAsyncLoadPercentage() now takes PostLoad into account - More async loading stats - Added AtomicallySetFlags/ClearFlags to UObject - Made FModuleManager thread safe. - Added FGCScopeGuard as means of preventing GC from executing from non-game thread - It's possible to disable async loading thread through ini settings. - Cancelling async loading will now also trigger GC - Implemented a basic version of async streaming priorities. Change 2410813 by Mikolaj Sieluzycki: Change Sleep in while loop to ConditionalSleep in FMultiReaderSingleWriterGT Change 2410734 by Mikolaj Sieluzycki: Make FModuleManager thread safe. Change 2399879 by Mikolaj Sieluzycki: Basic version of async streaming priorities. Change 2410707 by Mikolaj Sieluzycki: Implement conditional and no stat versions of sleep. Change 2371939 by Robert Manuszewski: Async Loading Improvements: adding more stats (accumulators) Change 2372403 by Robert Manuszewski: Fixing compile errors when STATs are not enabled Change 2371526 by Robert Manuszewski: AsyncLoading Improvements (WIP) Change 2407198 by Robert Manuszewski: Re-implementing delegate fixes for Async Loading Change 2407425 by Robert Manuszewski: Re-implementing cancelling async loading in the async loading branch. Change 2484362 by Robert Manuszewski: Making it possible to disable async loading thread through ini settings. Change 2484744 by Robert Manuszewski: Minimizing locks in GC and other threads when handling UObjects Change 2480190 by Robert Manuszewski: Fixing infinite stall after canceling async loading in non-cooked builds Change 2484268 by Robert Manuszewski: Fixing crash when allocating permanent object pool. Change 2489761 by Robert Manuszewski: Fixing BulkData using linker archive on the main thread even if the linker was created on the async loading thread. Change 2493624 by Robert Manuszewski: Cancelling async loading will now also trigger GC Change 2487881 by Robert Manuszewski: Making ShaderIdMap operations thread safe. Change 2488067 by Robert Manuszewski: Fixing GetAsyncLoadPercentage. It will now also respect PostLoad. Change 2458640 by Robert Manuszewski: Fixing crash in PIE Change 2458825 by Robert Manuszewski: Fixing a few crashes when streaming and the package is missing. Change 2476935 by Robert Manuszewski: Fixing crash while async loading ANavigationData Change 2477361 by Robert Manuszewski: Fixing crashes in cooked game Change 2480095 by Robert Manuszewski: Making FUObjectArray more thread safe Change 2475443 by Robert Manuszewski: Re-enabling single-threaded async loading path for the editor and platforms that don't support multithreading. Change 2475458 by Robert Manuszewski: Making sure bulk data is only loaded on a separate thread if it's not being loaded on the async loading thread. Change 2476661 by Robert Manuszewski: Fixing FlushAsyncLoading not flushing everything Change 2401089 by Jaroslaw Surowiec: Core - Added AtomicallySetFlags/ClearFlags to UObject, added a comment to ThisThreadAtomicallyClearedRFUnreachable [CL 2498249 by Robert Manuszewski in Main branch]
2015-04-01 03:03:18 -04:00
const FName RedirectedObjectName = FLinkerLoad::FindNewNameForClass(*ObjectName, false);
if (!RedirectedObjectName.IsNone())
{
FocusObject = FindObject<UClass>(ANY_PACKAGE, *RedirectedObjectName.ToString());
}
}
if (FocusObject)
{
TArray< UObject* > Objects;
Objects.Add(FocusObject);
GEditor->SyncBrowserToObjects(Objects);
}
}
}