You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
Icon is only visible if content is available for the editor in question. Split editor settings into two groups - one is persistent settings and one is progress/state. Tutorials record their dismissed state, so users can permenantly disable the 'nag' for a particular tutorial. Tutorial content now solidifies when the mouse is hovered over it, so it can be made easier to read. Fixed crash on startup if an intro tutorial was displaying rich text. Also fixed crash for TTP# 345094, where a zero-length tutorial was being accessed. [CL 2275934 by Thomas Sarkanen in Main branch]
239 lines
7.1 KiB
C++
239 lines
7.1 KiB
C++
// Copyright 1998-2014 Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "IntroTutorialsPrivatePCH.h"
|
|
#include "STutorialRoot.h"
|
|
#include "SEditorTutorials.h"
|
|
#include "EditorTutorialSettings.h"
|
|
#include "TutorialStateSettings.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, FSimpleDelegate InOnTutorialClosed, FSimpleDelegate InOnTutorialExited)
|
|
{
|
|
if(InTutorial != nullptr)
|
|
{
|
|
CurrentTutorial = InTutorial;
|
|
|
|
bool bHaveSeenTutorial = false;
|
|
CurrentTutorialStage = bInRestart ? 0 : GetDefault<UTutorialStateSettings>()->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 = false;
|
|
if (!InNavigationWindow.IsValid())
|
|
{
|
|
bIsNavigationWindow = TutorialWidget.Value.Pin()->IsNavigationVisible();
|
|
}
|
|
else
|
|
{
|
|
bIsNavigationWindow = (TutorialWidget.Value.Pin()->GetParentWindow() == InNavigationWindow.Pin());
|
|
}
|
|
TutorialWidget.Value.Pin()->LaunchTutorial(bIsNavigationWindow, InOnTutorialClosed, InOnTutorialExited);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void STutorialRoot::CloseAllTutorialContent()
|
|
{
|
|
for (auto& TutorialWidget : TutorialWidgets)
|
|
{
|
|
if (TutorialWidget.Value.IsValid())
|
|
{
|
|
TutorialWidget.Value.Pin()->HideContent();
|
|
}
|
|
}
|
|
}
|
|
|
|
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<UTutorialStateSettings>()->RecordProgress(CurrentTutorial, CurrentTutorialStage);
|
|
GetMutableDefault<UTutorialStateSettings>()->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)
|
|
{
|
|
int32 PreviousTutorialStage = CurrentTutorialStage;
|
|
if (CurrentTutorialStage > 0)
|
|
{
|
|
CurrentTutorial->HandleTutorialStageEnded(CurrentTutorial->Stages[CurrentTutorialStage].Name);
|
|
}
|
|
|
|
CurrentTutorialStage = FMath::Max(0, CurrentTutorialStage - 1);
|
|
|
|
if (PreviousTutorialStage != CurrentTutorialStage)
|
|
{
|
|
CurrentTutorial->HandleTutorialStageStarted(CurrentTutorial->Stages[CurrentTutorialStage].Name);
|
|
}
|
|
}
|
|
}
|
|
|
|
void STutorialRoot::GoToNextStage(TWeakPtr<SWindow> InNavigationWindow)
|
|
{
|
|
if(CurrentTutorial != nullptr)
|
|
{
|
|
UEditorTutorial* PreviousTutorial = CurrentTutorial;
|
|
int32 PreviousTutorialStage = CurrentTutorialStage;
|
|
CurrentTutorial->HandleTutorialStageEnded(CurrentTutorial->Stages[CurrentTutorialStage].Name);
|
|
|
|
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, FSimpleDelegate(), FSimpleDelegate());
|
|
}
|
|
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<UTutorialStateSettings>()->RecordProgress(CurrentTutorial, CurrentTutorialStage);
|
|
}
|
|
|
|
if (CurrentTutorial != nullptr && CurrentTutorialStage < CurrentTutorial->Stages.Num() && (CurrentTutorial != PreviousTutorial || CurrentTutorialStage != PreviousTutorialStage))
|
|
{
|
|
CurrentTutorial->HandleTutorialStageStarted(CurrentTutorial->Stages[CurrentTutorialStage].Name);
|
|
}
|
|
}
|
|
}
|
|
|
|
#undef LOCTEXT_NAMESPACE |