Tutorials 2.0 - Initial version

NOTE: Old tutorials not deprecated (yet), but widget highlights in old tutorials will stop working with this change!

Added new Blueprintable UEditorTutorial object.
Added suite of widgets and details customizations to display tutorials.
New system is available on command line switch -NewTutorials.

Slate changes:
Tag names are now stored in SWidgets, rather than simply being discarded.
Removed STutorialWrapper in favour of using Tags.
Added Tags to more multibox widgets, so virtually all can now be picked.
Added SWindow::HasOverlay so we dont attempt to add overlays to widows that cannot have them.

[CL 2244216 by Thomas Sarkanen in Main branch]
This commit is contained in:
Thomas Sarkanen
2014-08-05 09:04:35 -04:00
committed by UnrealBot
parent 1109c68e93
commit a27980dcf0
66 changed files with 3845 additions and 793 deletions

View File

@@ -0,0 +1,199 @@
// Copyright 1998-2014 Epic Games, Inc. All Rights Reserved.
#include "IntroTutorialsPrivatePCH.h"
#include "STutorialRoot.h"
#include "SEditorTutorials.h"
#include "EditorTutorialSettings.h"
#define LOCTEXT_NAMESPACE "STutorialRoot"
void STutorialRoot::Construct(const FArguments& InArgs)
{
CurrentTutorial = nullptr;
CurrentTutorialStage = 0;
ChildSlot
[
SNullWidget::NullWidget
];
}
void STutorialRoot::MaybeAddOverlay(TSharedRef<SWindow> InWindow)
{
if(InWindow->HasOverlay())
{
// check we dont already have a widget overlay for this window
TWeakPtr<SEditorTutorials>* FoundWidget = TutorialWidgets.Find(InWindow);
if(FoundWidget == nullptr)
{
TSharedPtr<SEditorTutorials> TutorialWidget = nullptr;
InWindow->AddOverlaySlot()
[
SNew(SHorizontalBox)
+SHorizontalBox::Slot()
.VAlign(VAlign_Fill)
.HAlign(HAlign_Fill)
[
SAssignNew(TutorialWidget, SEditorTutorials)
.ParentWindow(InWindow)
.OnNextClicked(FOnNextClicked::CreateSP(this, &STutorialRoot::HandleNextClicked))
.OnBackClicked(FSimpleDelegate::CreateSP(this, &STutorialRoot::HandleBackClicked))
.OnHomeClicked(FSimpleDelegate::CreateSP(this, &STutorialRoot::HandleHomeClicked))
.OnGetCurrentTutorial(FOnGetCurrentTutorial::CreateSP(this, &STutorialRoot::HandleGetCurrentTutorial))
.OnGetCurrentTutorialStage(FOnGetCurrentTutorialStage::CreateSP(this, &STutorialRoot::HandleGetCurrentTutorialStage))
.OnLaunchTutorial(FOnLaunchTutorial::CreateSP(this, &STutorialRoot::LaunchTutorial))
]
];
FoundWidget = &TutorialWidgets.Add(InWindow, TutorialWidget);
FoundWidget->Pin()->RebuildCurrentContent();
}
}
TArray<TSharedRef<SWindow>> ChildWindows = InWindow->GetChildWindows();
for(auto& ChildWindow : ChildWindows)
{
MaybeAddOverlay(ChildWindow);
}
}
void STutorialRoot::Tick(const FGeometry& AllottedGeometry, const double InCurrentTime, const float InDeltaTime)
{
TArray<TSharedRef<SWindow>> Windows = FSlateApplication::Get().GetInteractiveTopLevelWindows();
for(auto& Window : Windows)
{
MaybeAddOverlay(Window);
}
}
void STutorialRoot::SummonTutorialBrowser(TSharedRef<SWindow> InWindow, const FString& InFilter)
{
TWeakPtr<SEditorTutorials>* FoundWidget = TutorialWidgets.Find(InWindow);
if(FoundWidget != nullptr && FoundWidget->IsValid())
{
FoundWidget->Pin()->ShowBrowser(InFilter);
}
}
void STutorialRoot::LaunchTutorial(UEditorTutorial* InTutorial, bool bInRestart, TWeakPtr<SWindow> InNavigationWindow)
{
if(InTutorial != nullptr)
{
CurrentTutorial = InTutorial;
bool bHaveSeenTutorial = false;
CurrentTutorialStage = bInRestart ? 0 : GetDefault<UEditorTutorialSettings>()->GetProgress(CurrentTutorial, bHaveSeenTutorial);
// launch tutorial for all windows we wrap - any tutorial can display over any window
for(auto& TutorialWidget : TutorialWidgets)
{
if(TutorialWidget.Value.IsValid())
{
bool bIsNavigationWindow = InNavigationWindow.IsValid() && TutorialWidget.Value.Pin()->GetParentWindow() == InNavigationWindow.Pin();
TutorialWidget.Value.Pin()->LaunchTutorial(bIsNavigationWindow);
}
}
}
}
void STutorialRoot::HandleNextClicked(TWeakPtr<SWindow> InNavigationWindow)
{
GoToNextStage(InNavigationWindow);
for(auto& TutorialWidget : TutorialWidgets)
{
if(TutorialWidget.Value.IsValid())
{
TSharedPtr<SEditorTutorials> PinnedTutorialWidget = TutorialWidget.Value.Pin();
PinnedTutorialWidget->RebuildCurrentContent();
}
}
}
void STutorialRoot::HandleBackClicked()
{
GoToPreviousStage();
for(auto& TutorialWidget : TutorialWidgets)
{
if(TutorialWidget.Value.IsValid())
{
TSharedPtr<SEditorTutorials> PinnedTutorialWidget = TutorialWidget.Value.Pin();
PinnedTutorialWidget->RebuildCurrentContent();
}
}
}
void STutorialRoot::HandleHomeClicked()
{
if(CurrentTutorial != nullptr)
{
GetMutableDefault<UEditorTutorialSettings>()->RecordProgress(CurrentTutorial, CurrentTutorialStage);
GetMutableDefault<UEditorTutorialSettings>()->SaveProgress();
}
CurrentTutorial = nullptr;
CurrentTutorialStage = 0;
for(auto& TutorialWidget : TutorialWidgets)
{
if(TutorialWidget.Value.IsValid())
{
TSharedPtr<SEditorTutorials> PinnedTutorialWidget = TutorialWidget.Value.Pin();
PinnedTutorialWidget->RebuildCurrentContent();
}
}
}
UEditorTutorial* STutorialRoot::HandleGetCurrentTutorial()
{
return CurrentTutorial;
}
int32 STutorialRoot::HandleGetCurrentTutorialStage()
{
return CurrentTutorialStage;
}
void STutorialRoot::AddReferencedObjects( FReferenceCollector& Collector )
{
if(CurrentTutorial != nullptr)
{
Collector.AddReferencedObject(CurrentTutorial);
}
}
void STutorialRoot::GoToPreviousStage()
{
if(CurrentTutorial != nullptr)
{
CurrentTutorialStage = FMath::Max(0, CurrentTutorialStage - 1);
}
}
void STutorialRoot::GoToNextStage(TWeakPtr<SWindow> InNavigationWindow)
{
if(CurrentTutorial != nullptr)
{
if(CurrentTutorialStage + 1 >= CurrentTutorial->Stages.Num() && FName(*CurrentTutorial->NextTutorial.AssetLongPathname) != NAME_None)
{
TSubclassOf<UEditorTutorial> NextTutorialClass = LoadClass<UEditorTutorial>(NULL, *CurrentTutorial->NextTutorial.AssetLongPathname, NULL, LOAD_None, NULL);
if(NextTutorialClass != nullptr)
{
LaunchTutorial(NextTutorialClass->GetDefaultObject<UEditorTutorial>(), true, InNavigationWindow);
}
else
{
FSlateNotificationManager::Get().AddNotification(FNotificationInfo(FText::Format(LOCTEXT("TutorialNotFound", "Could not start next tutorial {0}"), FText::FromString(CurrentTutorial->NextTutorial.AssetLongPathname))));
}
}
else
{
CurrentTutorialStage = FMath::Min(CurrentTutorialStage + 1, CurrentTutorial->Stages.Num() - 1);
GetMutableDefault<UEditorTutorialSettings>()->RecordProgress(CurrentTutorial, CurrentTutorialStage);
}
}
}
#undef LOCTEXT_NAMESPACE