EVisibility SBlueprintEditorSelectedDebugObjectWidget::IsSelectDebugObjectButtonVisible() const
{
	check(GetBlueprintObj());
	if (UObject* DebugObj = GetBlueprintObj()->GetObjectBeingDebugged())
	{
		if (AActor* Actor = Cast<AActor>(DebugObj))
		{
			return EVisibility::Visible;
		}
	}
	return EVisibility::Collapsed;
}
TSharedPtr<FString> SBlueprintEditorSelectedDebugObjectWidget::GetDebugWorldName() const
{
	check(GetBlueprintObj());
	check(DebugWorlds.Num() == DebugWorldNames.Num());
	if (UObject* DebugObj = GetBlueprintObj()->GetObjectBeingDebugged())
	{
		for (int32 WorldIdx = 0; WorldIdx < DebugWorlds.Num(); ++WorldIdx)
		{
			if (DebugObj->IsIn(DebugWorlds[WorldIdx].Get()))
			{
				return DebugWorldNames[WorldIdx];
			}
		}
	}
	return DebugWorldNames[0];

}
TSharedPtr<FString> SBlueprintEditorSelectedDebugObjectWidget::GetDebugObjectName() const
{
	check(GetBlueprintObj());
	check(DebugObjects.Num() == DebugObjectNames.Num());
	if (UObject* DebugObj = GetBlueprintObj()->GetObjectBeingDebugged())
	{
		for (int32 ObjectIndex = 0; ObjectIndex < DebugObjects.Num(); ++ObjectIndex)
		{
			if (DebugObjects[ObjectIndex].IsValid() && (DebugObjects[ObjectIndex].Get() == DebugObj))
			{
				return DebugObjectNames[ObjectIndex];
			}
		}
	}

	return DebugObjectNames[0];
}
void SBlueprintEditorSelectedDebugObjectWidget::Tick(const FGeometry& AllottedGeometry, const double InCurrentTime, const float InDeltaTime)
{
	if (GetBlueprintObj())
	{
		if (UObject* Object = GetBlueprintObj()->GetObjectBeingDebugged())
		{
			if (Object != LastObjectObserved.Get())
			{
				LastObjectObserved = Object;

				GenerateDebugObjectNames(false);

				TSharedPtr<FString> NewSelection;
				for (int32 Index = 0; Index < DebugObjects.Num(); ++Index)
				{
					if (DebugObjects[Index] == Object)
					{
						NewSelection = DebugObjectNames[Index];
						break;
					}
				}

				if (!NewSelection.IsValid())
				{
					NewSelection = DebugObjectNames[0];
				}

				DebugObjectsComboBox->SetSelectedItem(NewSelection);
			}
		}
		else
		{
			LastObjectObserved = NULL;

			// If the object name is a name (rather than the 'No debug selected' string then regenerate the names (which will reset the combo box) as the object is invalid.
			TSharedPtr<FString> CurrentString = DebugObjectsComboBox->GetSelectedItem();
			if (*CurrentString != GetNoDebugString())
			{
				GenerateDebugObjectNames(false);
			}
		}
	}
}
FGraphAppearanceInfo FWidgetBlueprintEditor::GetGraphAppearance(UEdGraph* InGraph) const
{
	FGraphAppearanceInfo AppearanceInfo = FBlueprintEditor::GetGraphAppearance(InGraph);

	if ( GetBlueprintObj()->IsA(UWidgetBlueprint::StaticClass()) )
	{
		AppearanceInfo.CornerText = LOCTEXT("AppearanceCornerText", "WIDGET BLUEPRINT");
	}

	return AppearanceInfo;
}
void FSCSEditorViewportClient::BeginTransaction(const FText& Description)
{
	//UE_LOG(LogSCSEditorViewport, Log, TEXT("FSCSEditorViewportClient::BeginTransaction() pre: %s %08x"), SessionName, *((uint32*)&ScopedTransaction));

	if(!ScopedTransaction)
	{
		ScopedTransaction = new FScopedTransaction(Description);

		auto BlueprintEditor = BlueprintEditorPtr.Pin();
		if (BlueprintEditor.IsValid())
		{
			UBlueprint* PreviewBlueprint = BlueprintEditor->GetBlueprintObj();
			if (PreviewBlueprint != nullptr)
			{
				FBlueprintEditorUtils::MarkBlueprintAsModified(PreviewBlueprint);
			}

			TArray<FSCSEditorTreeNodePtrType> SelectedNodes = BlueprintEditor->GetSelectedSCSEditorTreeNodes();
			for(auto SelectedSCSNodeIter(SelectedNodes.CreateIterator()); SelectedSCSNodeIter; ++SelectedSCSNodeIter)
			{
				FSCSEditorTreeNodePtrType Node = *SelectedSCSNodeIter;
				if(Node.IsValid())
				{
					if(USCS_Node* SCS_Node = Node->GetSCSNode())
					{
						SCS_Node->Modify();
					}

					// Modify both the component template and the instance in the preview actor (provided there is one)
					UActorComponent* ComponentTemplate = Node->GetEditableComponentTemplate(PreviewBlueprint);
					if (ComponentTemplate != nullptr)
					{
						ComponentTemplate->SetFlags(RF_Transactional);
						ComponentTemplate->Modify();
					}

					AActor* PreviewActor = GetPreviewActor();
					if (PreviewActor)
					{
						UActorComponent* ComponentPreviewInstance = Node->FindComponentInstanceInActor(PreviewActor);
						if (ComponentPreviewInstance != nullptr)
						{
							ComponentPreviewInstance->SetFlags(RF_Transactional);
							ComponentPreviewInstance->Modify();
						}
					}
				}
			}
		}
	}

	//UE_LOG(LogSCSEditorViewport, Log, TEXT("FSCSEditorViewportClient::BeginTransaction() post: %s %08x"), SessionName, *((uint32*)&ScopedTransaction));
}
void SBlueprintEditorSelectedDebugObjectWidget::SelectedDebugObject_OnClicked()
{
	if (UObject* DebugObj = GetBlueprintObj()->GetObjectBeingDebugged())
	{
		if (AActor* Actor = Cast<AActor>(DebugObj))
		{
			GEditor->SelectNone(false, true, false);
			GEditor->SelectActor(Actor, true, true, true);
			GUnrealEd->Exec(Actor->GetWorld(), TEXT("CAMERA ALIGN ACTIVEVIEWPORTONLY"));
		}
	}
}
void SBlueprintEditorSelectedDebugObjectWidget::DebugObjectSelectionChanged(TSharedPtr<FString> NewSelection, ESelectInfo::Type SelectInfo)
{
	check(DebugObjects.Num() == DebugObjectNames.Num());
	for (int32 ObjectIndex = 0; ObjectIndex < DebugObjectNames.Num(); ++ObjectIndex)
	{
		if (*DebugObjectNames[ObjectIndex] == *NewSelection)
		{
			UObject* DebugObj = DebugObjects[ObjectIndex].IsValid() ? DebugObjects[ObjectIndex].Get() : NULL;
			GetBlueprintObj()->SetObjectBeingDebugged(DebugObj);
		}
	}
}
void SBlueprintEditorSelectedDebugObjectWidget::OnRefresh()
{
	if (GetBlueprintObj())
	{
		GenerateDebugWorldNames(false);
		if (UObject* Object = GetBlueprintObj()->GetObjectBeingDebugged())
		{
			GenerateDebugObjectNames(false);
			if (AActor* Actor = Cast<AActor>(Object))
			{
				DebugObjectsComboBox->SetSelectedItem(MakeShareable(new FString(Actor->GetActorLabel())));
			}
			else
			{
				DebugObjectsComboBox->SetSelectedItem(MakeShareable(new FString(Object->GetName())));
			}
		}
		else
		{
			// If we didnt find and object its probably a good idea to regenerate the names now - this will also ensure the combo box has a valid selection.
			GenerateDebugObjectNames(false);
		}
	}
}
void SBlueprintEditorSelectedDebugObjectWidget::DebugWorldSelectionChanged(TSharedPtr<FString> NewSelection, ESelectInfo::Type SelectInfo)
{
	if (!NewSelection.IsValid())
	{
		return;
	}

	check(DebugObjects.Num() == DebugObjectNames.Num());
	for (int32 WorldIdx = 0; WorldIdx < DebugWorldNames.Num(); ++WorldIdx)
	{
		if (*DebugWorldNames[WorldIdx] == *NewSelection)
		{
			GetBlueprintObj()->SetWorldBeingDebugged(DebugWorlds[WorldIdx].Get());
			GenerateDebugObjectNames(false);
		}
	}
}
UScriptBlueprint* FScriptBlueprintEditor::GetScriptBlueprintObj() const
{
	return Cast<UScriptBlueprint>(GetBlueprintObj());
}
bool FSCSEditorViewportClient::InputWidgetDelta( FViewport* Viewport, EAxisList::Type CurrentAxis, FVector& Drag, FRotator& Rot, FVector& Scale )
{
	bool bHandled = false;
	if(bIsManipulating && CurrentAxis != EAxisList::None)
	{
		bHandled = true;
		AActor* PreviewActor = GetPreviewActor();
		auto BlueprintEditor = BlueprintEditorPtr.Pin();
		if (PreviewActor && BlueprintEditor.IsValid())
		{
			TArray<FSCSEditorTreeNodePtrType> SelectedNodes = BlueprintEditor->GetSelectedSCSEditorTreeNodes();
			if(SelectedNodes.Num() > 0)
			{
				FVector ModifiedScale = Scale;
				if( GEditor->UsePercentageBasedScaling() )
				{
					ModifiedScale = Scale * ((GEditor->GetScaleGridSize() / 100.0f) / GEditor->GetGridSize());
				}

				TSet<USceneComponent*> UpdatedComponents;

				for(auto It(SelectedNodes.CreateIterator());It;++It)
				{
					FSCSEditorTreeNodePtrType SelectedNodePtr = *It;
					// Don't allow editing of a root node, inherited SCS node or child node that also has a movable (non-root) parent node selected
					const bool bCanEdit = !SelectedNodePtr->IsRootComponent() && !SelectedNodePtr->IsInherited()
						&& !IsMovableParentNodeSelected(SelectedNodePtr, SelectedNodes);

					if(bCanEdit)
					{
						USceneComponent* SceneComp = Cast<USceneComponent>(SelectedNodePtr->FindComponentInstanceInActor(PreviewActor));
						USceneComponent* SelectedTemplate = Cast<USceneComponent>(SelectedNodePtr->GetEditableComponentTemplate(BlueprintEditor->GetBlueprintObj()));
						if(SceneComp != NULL && SelectedTemplate != NULL)
						{
							// Cache the current default values for propagation
							FVector OldRelativeLocation = SelectedTemplate->RelativeLocation;
							FRotator OldRelativeRotation = SelectedTemplate->RelativeRotation;
							FVector OldRelativeScale3D = SelectedTemplate->RelativeScale3D;

							// Adjust the deltas as necessary
							FComponentEditorUtils::AdjustComponentDelta(SceneComp, Drag, Rot);

							TSharedPtr<ISCSEditorCustomization> Customization = BlueprintEditor->CustomizeSCSEditor(SceneComp);
							if(Customization.IsValid() && Customization->HandleViewportDrag(SceneComp, SelectedTemplate, Drag, Rot, ModifiedScale, GetWidgetLocation()))
							{
								UpdatedComponents.Add(SceneComp);
								UpdatedComponents.Add(SelectedTemplate);
							}
							else
							{
								// Apply delta to the preview actor's scene component
								GEditor->ApplyDeltaToComponent(
										SceneComp,
										true,
										&Drag,
										&Rot,
										&ModifiedScale,
										SceneComp->RelativeLocation );
								UpdatedComponents.Add(SceneComp);

							// Apply delta to the template component object
								GEditor->ApplyDeltaToComponent(
										SelectedTemplate,
										true,
										&Drag,
										&Rot,
										&ModifiedScale,
										SelectedTemplate->RelativeLocation );
								UpdatedComponents.Add(SelectedTemplate);
							}

							UBlueprint* PreviewBlueprint = UBlueprint::GetBlueprintFromClass(PreviewActor->GetClass());
							if(PreviewBlueprint != NULL)
							{
								// Like PostEditMove(), but we only need to re-run construction scripts
								if(PreviewBlueprint && PreviewBlueprint->bRunConstructionScriptOnDrag)
								{
									PreviewActor->RerunConstructionScripts();
								}

								SceneComp->PostEditComponentMove(true); // @TODO HACK passing 'finished' every frame...

								// If a constraint, copy back updated constraint frames to template
								UPhysicsConstraintComponent* ConstraintComp = Cast<UPhysicsConstraintComponent>(SceneComp);
								UPhysicsConstraintComponent* TemplateComp = Cast<UPhysicsConstraintComponent>(SelectedTemplate);
								if(ConstraintComp && TemplateComp)
								{
									TemplateComp->ConstraintInstance.CopyConstraintGeometryFrom(&ConstraintComp->ConstraintInstance);
								}

								// Iterate over all the active archetype instances and propagate the change(s) to the matching component instance
								TArray<UObject*> ArchetypeInstances;
								if(SelectedTemplate->HasAnyFlags(RF_ArchetypeObject))
								{
									SelectedTemplate->GetArchetypeInstances(ArchetypeInstances);
									for(int32 InstanceIndex = 0; InstanceIndex < ArchetypeInstances.Num(); ++InstanceIndex)
									{
										SceneComp = Cast<USceneComponent>(ArchetypeInstances[InstanceIndex]);
										if(SceneComp && SceneComp->GetOwner() != PreviewActor)
										{
											FComponentEditorUtils::ApplyDefaultValueChange(SceneComp, SceneComp->RelativeLocation, OldRelativeLocation, SelectedTemplate->RelativeLocation);
											FComponentEditorUtils::ApplyDefaultValueChange(SceneComp, SceneComp->RelativeRotation, OldRelativeRotation, SelectedTemplate->RelativeRotation);
											FComponentEditorUtils::ApplyDefaultValueChange(SceneComp, SceneComp->RelativeScale3D,  OldRelativeScale3D,  SelectedTemplate->RelativeScale3D);
										}
									}
								}
								else if(UObject* Outer = SelectedTemplate->GetOuter())
								{
									Outer->GetArchetypeInstances(ArchetypeInstances);
									for(int32 InstanceIndex = 0; InstanceIndex < ArchetypeInstances.Num(); ++InstanceIndex)
									{
										if(ArchetypeInstances[InstanceIndex] != PreviewActor)
										{
											SceneComp = static_cast<USceneComponent*>(FindObjectWithOuter(ArchetypeInstances[InstanceIndex], SelectedTemplate->GetClass(), SelectedTemplate->GetFName()));
											if(SceneComp)
											{
												FComponentEditorUtils::ApplyDefaultValueChange(SceneComp, SceneComp->RelativeLocation, OldRelativeLocation, SelectedTemplate->RelativeLocation);
												FComponentEditorUtils::ApplyDefaultValueChange(SceneComp, SceneComp->RelativeRotation, OldRelativeRotation, SelectedTemplate->RelativeRotation);
												FComponentEditorUtils::ApplyDefaultValueChange(SceneComp, SceneComp->RelativeScale3D,  OldRelativeScale3D,  SelectedTemplate->RelativeScale3D);
											}
										}
									}
								}
							}
						}
					}
				}
				GUnrealEd->RedrawLevelEditingViewports();
			}
		}

		Invalidate();
	}

	return bHandled;
}
EVisibility SBlueprintEditorSelectedDebugObjectWidget::ShouldShowDebugObjectPicker() const
{
	check(GetBlueprintObj());
	return FBlueprintEditorUtils::IsLevelScriptBlueprint(GetBlueprintObj()) ? EVisibility::Collapsed : EVisibility::Visible;
}
void SBlueprintEditorSelectedDebugObjectWidget::GenerateDebugObjectNames(bool bRestoreSelection)
{
	TSharedPtr<FString> OldSelection;

	// Store off the old selection
	if (bRestoreSelection && DebugObjectsComboBox.IsValid())
	{
		OldSelection = DebugObjectsComboBox->GetSelectedItem();
	}

	// Empty the lists of actors and regenerate them
	DebugObjects.Empty();
	DebugObjectNames.Empty();
	DebugObjects.Add(NULL);
	DebugObjectNames.Add(MakeShareable(new FString(GetNoDebugString())));

	// Grab custom objects that should always be visible, regardless of the world
	TArray<FCustomDebugObject> CustomDebugObjects;
	BlueprintEditor.Pin()->GetCustomDebugObjects(/*inout*/ CustomDebugObjects);

	for (const FCustomDebugObject& Entry : CustomDebugObjects)
	{
		if (Entry.NameOverride.IsEmpty())
		{
			AddDebugObject(Entry.Object);
		}
		else
		{
			AddDebugObjectWithName(Entry.Object, Entry.NameOverride);
		}
	}

	// Check for a specific debug world. If DebugWorld=NULL we take that as "any PIE world"
	UWorld* DebugWorld = NULL;
	if (DebugWorldsComboBox.IsValid())
	{
		TSharedPtr<FString> CurrentWorldSelection = DebugWorldsComboBox->GetSelectedItem();
		int32 SelectedIndex = DebugWorldNames.Find(CurrentWorldSelection);
		if (SelectedIndex > 0 && DebugWorldNames.IsValidIndex(SelectedIndex))
		{
			DebugWorld = DebugWorlds[SelectedIndex].Get();
		}
	}

	UWorld* PreviewWorld = NULL;
	TSharedPtr<SSCSEditorViewport> PreviewViewportPtr = BlueprintEditor.Pin()->GetSCSViewport();
	if (PreviewViewportPtr.IsValid())
	{
		PreviewWorld = PreviewViewportPtr->GetPreviewScene().GetWorld();
	}

	for (TObjectIterator<UObject> It; It; ++It)
	{
		UObject* TestObject = *It;

		// Skip Blueprint preview objects (don't allow them to be selected for debugging)
		if (PreviewWorld != NULL && TestObject->IsIn(PreviewWorld))
		{
			continue;
		}

		const bool bPassesFlags = !TestObject->HasAnyFlags(RF_PendingKill | RF_ClassDefaultObject);
		const bool bGeneratedByBlueprint = TestObject->GetClass()->ClassGeneratedBy == GetBlueprintObj();
		if (bPassesFlags && bGeneratedByBlueprint)
		{

			UObject *ObjOuter = TestObject;
			UWorld *ObjWorld = NULL;
			while (ObjWorld == NULL && ObjOuter != NULL)
			{
				ObjOuter = ObjOuter->GetOuter();
				ObjWorld = Cast<UWorld>(ObjOuter);
			}

			// Object not in any world
			if (!ObjWorld)
			{
				continue;
			}

			// Make check on owning level (not streaming level)
			if (ObjWorld->PersistentLevel && ObjWorld->PersistentLevel->OwningWorld)
			{
				ObjWorld = ObjWorld->PersistentLevel->OwningWorld;
			}

			// We have a specific debug world and the object isnt in it
			if (DebugWorld && ObjWorld != DebugWorld)
			{
				continue;
			}

			// We don't have a specific debug world, but the object isnt in a PIE world
			if (ObjWorld->WorldType != EWorldType::PIE)
			{
				continue;
			}

			AddDebugObject(TestObject);
		}
	}

	// Attempt to restore the old selection
	if (bRestoreSelection && DebugObjectsComboBox.IsValid())
	{
		bool bMatchFound = false;
		for (int32 ObjectIndex = 0; ObjectIndex < DebugObjectNames.Num(); ++ObjectIndex)
		{
			if (*DebugObjectNames[ObjectIndex] == *OldSelection)
			{
				DebugObjectsComboBox->SetSelectedItem(DebugObjectNames[ObjectIndex]);
				bMatchFound = true;
				break;
			}
		}

		// No match found, use the default option
		if (!bMatchFound)
		{
			DebugObjectsComboBox->SetSelectedItem(DebugObjectNames[0]);
		}
	}

	// Finally ensure we have a valid selection
	if (DebugObjectsComboBox.IsValid())
	{
		TSharedPtr<FString> CurrentSelection = DebugObjectsComboBox->GetSelectedItem();
		if (DebugObjectNames.Find(CurrentSelection) == INDEX_NONE)
		{
			if (DebugObjectNames.Num() > 0)
			{
				DebugObjectsComboBox->SetSelectedItem(DebugObjectNames[0]);
			}
			else
			{
				DebugObjectsComboBox->ClearSelection();
			}
		}

		DebugObjectsComboBox->RefreshOptions();
	}
}
UWidgetBlueprint* FWidgetBlueprintEditor::GetWidgetBlueprintObj() const
{
	return Cast<UWidgetBlueprint>(GetBlueprintObj());
}