// Copyright 1998-2014 Epic Games, Inc. All Rights Reserved. #include "IntroTutorialsPrivatePCH.h" #include "STutorialRoot.h" #include "SEditorTutorials.h" #include "EditorTutorialSettings.h" #include "TutorialStateSettings.h" #include "AssetEditorManager.h" #include "ToolkitManager.h" #define LOCTEXT_NAMESPACE "STutorialRoot" void STutorialRoot::Construct(const FArguments& InArgs) { CurrentTutorial = nullptr; CurrentTutorialStage = 0; ChildSlot [ SNullWidget::NullWidget ]; } void STutorialRoot::MaybeAddOverlay(TSharedRef InWindow) { if(InWindow->HasOverlay()) { // check we dont already have a widget overlay for this window TWeakPtr* FoundWidget = TutorialWidgets.Find(InWindow); if(FoundWidget == nullptr) { TSharedPtr 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> ChildWindows = InWindow->GetChildWindows(); for(auto& ChildWindow : ChildWindows) { MaybeAddOverlay(ChildWindow); } } void STutorialRoot::Tick(const FGeometry& AllottedGeometry, const double InCurrentTime, const float InDeltaTime) { TArray> Windows = FSlateApplication::Get().GetInteractiveTopLevelWindows(); for(auto& Window : Windows) { MaybeAddOverlay(Window); } } void STutorialRoot::SummonTutorialBrowser(TSharedRef InWindow, const FString& InFilter) { TWeakPtr* FoundWidget = TutorialWidgets.Find(InWindow); if(FoundWidget != nullptr && FoundWidget->IsValid()) { FoundWidget->Pin()->ShowBrowser(InFilter); } } void STutorialRoot::LaunchTutorial(UEditorTutorial* InTutorial, bool bInRestart, TWeakPtr InNavigationWindow, FSimpleDelegate InOnTutorialClosed, FSimpleDelegate InOnTutorialExited) { if(InTutorial != nullptr) { CurrentTutorial = InTutorial; bool bHaveSeenTutorial = false; CurrentTutorialStage = bInRestart ? 0 : GetDefault()->GetProgress(CurrentTutorial, bHaveSeenTutorial); // check if we should be launching this tutorial for an asset editor if(InTutorial->AssetToUse.IsValid()) { TArray AssetPaths; AssetPaths.Add(InTutorial->AssetToUse.AssetLongPathname); FAssetEditorManager::Get().OpenEditorsForAssets(AssetPaths); UObject* Asset = InTutorial->AssetToUse.ResolveObject(); if(Asset != nullptr) { TSharedPtr Toolkit = FToolkitManager::Get().FindEditorForAsset( Asset ); if(Toolkit.IsValid()) { InNavigationWindow = FSlateApplication::Get().FindWidgetWindow(Toolkit->GetToolkitHost()->GetParentWidget()); } } } // 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 InNavigationWindow) { GoToNextStage(InNavigationWindow); for(auto& TutorialWidget : TutorialWidgets) { if(TutorialWidget.Value.IsValid()) { TSharedPtr PinnedTutorialWidget = TutorialWidget.Value.Pin(); PinnedTutorialWidget->RebuildCurrentContent(); } } } void STutorialRoot::HandleBackClicked() { GoToPreviousStage(); for(auto& TutorialWidget : TutorialWidgets) { if(TutorialWidget.Value.IsValid()) { TSharedPtr PinnedTutorialWidget = TutorialWidget.Value.Pin(); PinnedTutorialWidget->RebuildCurrentContent(); } } } void STutorialRoot::HandleHomeClicked() { if(CurrentTutorial != nullptr) { GetMutableDefault()->RecordProgress(CurrentTutorial, CurrentTutorialStage); GetMutableDefault()->SaveProgress(); } CurrentTutorial = nullptr; CurrentTutorialStage = 0; for(auto& TutorialWidget : TutorialWidgets) { if(TutorialWidget.Value.IsValid()) { TSharedPtr 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 InNavigationWindow) { if(CurrentTutorial != nullptr) { UEditorTutorial* PreviousTutorial = CurrentTutorial; int32 PreviousTutorialStage = CurrentTutorialStage; if(CurrentTutorialStage < CurrentTutorial->Stages.Num()) { CurrentTutorial->HandleTutorialStageEnded(CurrentTutorial->Stages[CurrentTutorialStage].Name); } if(CurrentTutorialStage + 1 >= CurrentTutorial->Stages.Num() && FName(*CurrentTutorial->NextTutorial.AssetLongPathname) != NAME_None) { TSubclassOf NextTutorialClass = LoadClass(NULL, *CurrentTutorial->NextTutorial.AssetLongPathname, NULL, LOAD_None, NULL); if(NextTutorialClass != nullptr) { LaunchTutorial(NextTutorialClass->GetDefaultObject(), 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()->RecordProgress(CurrentTutorial, CurrentTutorialStage); } if (CurrentTutorial != nullptr && CurrentTutorialStage < CurrentTutorial->Stages.Num() && (CurrentTutorial != PreviousTutorial || CurrentTutorialStage != PreviousTutorialStage)) { CurrentTutorial->HandleTutorialStageStarted(CurrentTutorial->Stages[CurrentTutorialStage].Name); } } } #undef LOCTEXT_NAMESPACE