FWidget::EWidgetMode FSCSEditorViewportClient::GetWidgetMode() const { // Default to not drawing the widget FWidget::EWidgetMode ReturnWidgetMode = FWidget::WM_None; AActor* PreviewActor = GetPreviewActor(); if(!bIsSimulateEnabled && PreviewActor) { const TSharedPtr<FBlueprintEditor> BluePrintEditor = BlueprintEditorPtr.Pin(); if ( BluePrintEditor.IsValid() ) { TArray<FSCSEditorTreeNodePtrType> SelectedNodes = BluePrintEditor->GetSelectedSCSEditorTreeNodes(); const TArray<FSCSEditorTreeNodePtrType>& RootNodes = BluePrintEditor->GetSCSEditor()->GetRootComponentNodes(); // if the selected nodes array is empty, or only contains entries from the // root nodes array, or isn't visible in the preview actor, then don't display a transform widget for ( int32 CurrentNodeIndex=0; CurrentNodeIndex < SelectedNodes.Num(); CurrentNodeIndex++ ) { FSCSEditorTreeNodePtrType CurrentNodePtr = SelectedNodes[CurrentNodeIndex]; if (CurrentNodePtr.IsValid() && !RootNodes.Contains(CurrentNodePtr) && !CurrentNodePtr->IsRootComponent() && CurrentNodePtr->CanEditDefaults() && CurrentNodePtr->FindComponentInstanceInActor(PreviewActor)) { // a non-NULL, non-root item is selected, draw the widget ReturnWidgetMode = WidgetMode; break; } } } } return ReturnWidgetMode; }
void FSCSEditorViewportClient::DestroyPreview() { AActor* PreviewActor = GetPreviewActor(); if(PreviewActor != NULL) { check(PreviewScene); check(PreviewScene->GetWorld()); PreviewScene->GetWorld()->EditorDestroyActor(PreviewActor, false); } if(PreviewBlueprint != NULL) { if(PreviewBlueprint->SimpleConstructionScript != NULL && PreviewActor == PreviewBlueprint->SimpleConstructionScript->GetComponentEditorActorInstance()) { // Ensure that all editable component references are cleared PreviewBlueprint->SimpleConstructionScript->ClearEditorComponentReferences(); // Clear the reference to the preview actor instance PreviewBlueprint->SimpleConstructionScript->SetComponentEditorActorInstance(NULL); } PreviewBlueprint = NULL; } }
FVector FSCSEditorViewportClient::GetWidgetLocation() const { FVector Location = FVector::ZeroVector; AActor* PreviewActor = GetPreviewActor(); if(PreviewActor) { TArray<FSCSEditorTreeNodePtrType> SelectedNodes = BlueprintEditorPtr.Pin()->GetSelectedSCSEditorTreeNodes(); if(SelectedNodes.Num() > 0) { // Use the last selected item for the widget location USceneComponent* SceneComp = Cast<USceneComponent>(SelectedNodes.Last().Get()->FindComponentInstanceInActor(PreviewActor)); if( SceneComp ) { TSharedPtr<ISCSEditorCustomization> Customization = BlueprintEditorPtr.Pin()->CustomizeSCSEditor(SceneComp); FVector CustomLocation; if(Customization.IsValid() && Customization->HandleGetWidgetLocation(SceneComp, CustomLocation)) { Location = CustomLocation; } else { Location = SceneComp->GetComponentLocation(); } } } } return Location; }
void FSCSEditorViewportClient::Draw(const FSceneView* View, FPrimitiveDrawInterface* PDI) { FEditorViewportClient::Draw(View, PDI); bool bHitTesting = PDI->IsHitTesting(); AActor* PreviewActor = GetPreviewActor(); if(PreviewActor) { if(GUnrealEd != NULL) { TArray<FSCSEditorTreeNodePtrType> SelectedNodes = BlueprintEditorPtr.Pin()->GetSelectedSCSEditorTreeNodes(); for (int32 SelectionIndex = 0; SelectionIndex < SelectedNodes.Num(); ++SelectionIndex) { FSCSEditorTreeNodePtrType SelectedNode = SelectedNodes[SelectionIndex]; UActorComponent* Comp = SelectedNode->FindComponentInstanceInActor(PreviewActor); if(Comp != NULL && Comp->IsRegistered()) { // Try and find a visualizer TSharedPtr<FComponentVisualizer> Visualizer = GUnrealEd->FindComponentVisualizer(Comp->GetClass()); if (Visualizer.IsValid()) { Visualizer->DrawVisualization(Comp, View, PDI); } } } } } }
void FSCSEditorViewportClient::DrawCanvas( FViewport& InViewport, FSceneView& View, FCanvas& Canvas ) { AActor* PreviewActor = GetPreviewActor(); if(PreviewActor) { TGuardValue<bool> AutoRestore(GAllowActorScriptExecutionInEditor, true); const int32 HalfX = 0.5f * Viewport->GetSizeXY().X; const int32 HalfY = 0.5f * Viewport->GetSizeXY().Y; auto SelectedNodes = BlueprintEditorPtr.Pin()->GetSelectedSCSEditorTreeNodes(); if(bIsManipulating && SelectedNodes.Num() > 0) { USceneComponent* SceneComp = Cast<USceneComponent>(SelectedNodes[0]->FindComponentInstanceInActor(PreviewActor, true)); if(SceneComp) { const FVector WidgetLocation = GetWidgetLocation(); const FPlane Proj = View.Project(WidgetLocation); if(Proj.W > 0.0f) { const int32 XPos = HalfX + (HalfX * Proj.X); const int32 YPos = HalfY + (HalfY * (Proj.Y * -1)); DrawAngles(&Canvas, XPos, YPos, GetCurrentWidgetAxis(), GetWidgetMode(), GetWidgetCoordSystem().Rotator(), WidgetLocation); } } } } }
void FSCSEditorViewportClient::Tick(float DeltaSeconds) { FEditorViewportClient::Tick(DeltaSeconds); // Register the selection override delegate for the preview actor's components TSharedPtr<SSCSEditor> SCSEditor = BlueprintEditorPtr.Pin()->GetSCSEditor(); AActor* PreviewActor = GetPreviewActor(); if (PreviewActor != nullptr) { TInlineComponentArray<UPrimitiveComponent*> PrimitiveComponents; PreviewActor->GetComponents(PrimitiveComponents); for (int32 CompIdx = 0; CompIdx < PrimitiveComponents.Num(); ++CompIdx) { UPrimitiveComponent* PrimComponent = PrimitiveComponents[CompIdx]; if (!PrimComponent->SelectionOverrideDelegate.IsBound()) { SCSEditor->SetSelectionOverride(PrimComponent); } } } else { InvalidatePreview(false); } if ( PreviewActor != LastPreviewActor.Get() || PreviewActor == nullptr || IsRealtime() ) { LastPreviewActor = PreviewActor; Invalidate(); RefreshPreviewBounds(); } // Tick the preview scene world. if (!GIntraFrameDebuggingGameThread) { // Ensure that the preview actor instance is up-to-date for component editing (e.g. after compiling the Blueprint, the actor may be reinstanced outside of this class) if(PreviewActor != BlueprintEditorPtr.Pin()->GetBlueprintObj()->SimpleConstructionScript->GetComponentEditorActorInstance()) { BlueprintEditorPtr.Pin()->GetBlueprintObj()->SimpleConstructionScript->SetComponentEditorActorInstance(PreviewActor); } // Allow full tick only if preview simulation is enabled and we're not currently in an active SIE or PIE session if(bIsSimulateEnabled && GEditor->PlayWorld == NULL && !GEditor->bIsSimulatingInEditor) { PreviewScene->GetWorld()->Tick(IsRealtime() ? LEVELTICK_All : LEVELTICK_TimeOnly, DeltaSeconds); } else { PreviewScene->GetWorld()->Tick(IsRealtime() ? LEVELTICK_ViewportsOnly : LEVELTICK_TimeOnly, DeltaSeconds); } } }
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 FSCSEditorViewportClient::ProcessClick(class FSceneView& View, class HHitProxy* HitProxy, FKey Key, EInputEvent Event, uint32 HitX, uint32 HitY) { if(HitProxy) { if(HitProxy->IsA(HInstancedStaticMeshInstance::StaticGetType())) { HInstancedStaticMeshInstance* InstancedStaticMeshInstanceProxy = ( ( HInstancedStaticMeshInstance* )HitProxy ); TSharedPtr<ISCSEditorCustomization> Customization = BlueprintEditorPtr.Pin()->CustomizeSCSEditor(InstancedStaticMeshInstanceProxy->Component); if(Customization.IsValid() && Customization->HandleViewportClick(AsShared(), View, HitProxy, Key, Event, HitX, HitY)) { Invalidate(); } } else if(HitProxy->IsA(HActor::StaticGetType())) { HActor* ActorProxy = (HActor*)HitProxy; AActor* PreviewActor = GetPreviewActor(); if(ActorProxy && ActorProxy->Actor && ActorProxy->Actor == PreviewActor && ActorProxy->PrimComponent != NULL) { TInlineComponentArray<USceneComponent*> SceneComponents; ActorProxy->Actor->GetComponents(SceneComponents); for(auto CompIt = SceneComponents.CreateConstIterator(); CompIt; ++CompIt) { USceneComponent* CompInstance = *CompIt; TSharedPtr<ISCSEditorCustomization> Customization = BlueprintEditorPtr.Pin()->CustomizeSCSEditor(CompInstance); if (Customization.IsValid() && Customization->HandleViewportClick(AsShared(), View, HitProxy, Key, Event, HitX, HitY)) { break; } if (CompInstance == ActorProxy->PrimComponent) { const bool bIsCtrlKeyDown = Viewport->KeyState(EKeys::LeftControl) || Viewport->KeyState(EKeys::RightControl); if (BlueprintEditorPtr.IsValid()) { // Note: This will find and select any node associated with the component instance that's attached to the proxy (including visualizers) BlueprintEditorPtr.Pin()->FindAndSelectSCSEditorTreeNode(CompInstance, bIsCtrlKeyDown); } break; } } } Invalidate(); } // Pass to component vis manager //GUnrealEd->ComponentVisManager.HandleProxyForComponentVis(HitProxy); } }
void FSCSEditorViewportClient::DrawCanvas( FViewport& InViewport, FSceneView& View, FCanvas& Canvas ) { AActor* PreviewActor = GetPreviewActor(); if(PreviewActor) { if (GUnrealEd != NULL) { TArray<FSCSEditorTreeNodePtrType> SelectedNodes = BlueprintEditorPtr.Pin()->GetSelectedSCSEditorTreeNodes(); for (int32 SelectionIndex = 0; SelectionIndex < SelectedNodes.Num(); ++SelectionIndex) { FSCSEditorTreeNodePtrType SelectedNode = SelectedNodes[SelectionIndex]; UActorComponent* Comp = Cast<USceneComponent>(SelectedNode->FindComponentInstanceInActor(PreviewActor)); if (Comp != NULL && Comp->IsRegistered()) { // Try and find a visualizer TSharedPtr<FComponentVisualizer> Visualizer = GUnrealEd->FindComponentVisualizer(Comp->GetClass()); if (Visualizer.IsValid()) { Visualizer->DrawVisualizationHUD(Comp, &InViewport, &View, &Canvas); } } } } TGuardValue<bool> AutoRestore(GAllowActorScriptExecutionInEditor, true); const int32 HalfX = 0.5f * Viewport->GetSizeXY().X; const int32 HalfY = 0.5f * Viewport->GetSizeXY().Y; auto SelectedNodes = BlueprintEditorPtr.Pin()->GetSelectedSCSEditorTreeNodes(); if(bIsManipulating && SelectedNodes.Num() > 0) { USceneComponent* SceneComp = Cast<USceneComponent>(SelectedNodes[0]->FindComponentInstanceInActor(PreviewActor)); if(SceneComp) { const FVector WidgetLocation = GetWidgetLocation(); const FPlane Proj = View.Project(WidgetLocation); if(Proj.W > 0.0f) { const int32 XPos = HalfX + (HalfX * Proj.X); const int32 YPos = HalfY + (HalfY * (Proj.Y * -1)); DrawAngles(&Canvas, XPos, YPos, GetCurrentWidgetAxis(), GetWidgetMode(), GetWidgetCoordSystem().Rotator(), WidgetLocation); } } } } }
void FSCSEditorViewportClient::TrackingStopped() { if( bIsManipulating ) { // Re-run construction scripts if we haven't done so yet (so that the components in the preview actor can update their transforms) AActor* PreviewActor = GetPreviewActor(); if(PreviewActor != NULL && PreviewBlueprint != NULL && !PreviewBlueprint->bRunConstructionScriptOnDrag) { PreviewActor->RerunConstructionScripts(); } // End transaction bIsManipulating = false; EndTransaction(); // Restore component delta modification GEditor->DisableDeltaModification(false); } }
void FSCSEditorViewportClient::FocusViewportToSelection() { AActor* PreviewActor = GetPreviewActor(); if(PreviewActor) { TArray<FSCSEditorTreeNodePtrType> SelectedNodes = BlueprintEditorPtr.Pin()->GetSelectedSCSEditorTreeNodes(); if(SelectedNodes.Num() > 0) { // Use the last selected item for the widget location USceneComponent* SceneComp = Cast<USceneComponent>(SelectedNodes.Last()->FindComponentInstanceInActor(PreviewActor)); if( SceneComp ) { FocusViewportOnBox( SceneComp->Bounds.GetBox() ); } } else { FocusViewportOnBox( PreviewActor->GetComponentsBoundingBox( true ) ); } } }
void FSCSEditorViewportClient::RefreshPreviewBounds() { AActor* PreviewActor = GetPreviewActor(); if(PreviewActor) { // Compute actor bounds as the sum of its visible parts TInlineComponentArray<UPrimitiveComponent*> PrimitiveComponents; PreviewActor->GetComponents(PrimitiveComponents); PreviewActorBounds = FBoxSphereBounds(ForceInitToZero); for(auto CompIt = PrimitiveComponents.CreateConstIterator(); CompIt; ++CompIt) { // Aggregate primitive components that either have collision enabled or are otherwise visible components in-game UPrimitiveComponent* PrimComp = *CompIt; if(PrimComp->IsRegistered() && (!PrimComp->bHiddenInGame || PrimComp->IsCollisionEnabled()) && PrimComp->Bounds.SphereRadius < HALF_WORLD_MAX) { PreviewActorBounds = PreviewActorBounds + PrimComp->Bounds; } } } }
FMatrix FSCSEditorViewportClient::GetWidgetCoordSystem() const { FMatrix Matrix = FMatrix::Identity; if( GetWidgetCoordSystemSpace() == COORD_Local ) { AActor* PreviewActor = GetPreviewActor(); auto BlueprintEditor = BlueprintEditorPtr.Pin(); if (PreviewActor && BlueprintEditor.IsValid()) { TArray<FSCSEditorTreeNodePtrType> SelectedNodes = BlueprintEditor->GetSelectedSCSEditorTreeNodes(); if(SelectedNodes.Num() > 0) { const auto SelectedNode = SelectedNodes.Last(); USceneComponent* SceneComp = SelectedNode.IsValid() ? Cast<USceneComponent>(SelectedNode->FindComponentInstanceInActor(PreviewActor)) : NULL; if( SceneComp ) { TSharedPtr<ISCSEditorCustomization> Customization = BlueprintEditor->CustomizeSCSEditor(SceneComp); FMatrix CustomTransform; if(Customization.IsValid() && Customization->HandleGetWidgetTransform(SceneComp, CustomTransform)) { Matrix = CustomTransform; } else { Matrix = FRotationMatrix( SceneComp->GetComponentRotation() ); } } } } } if(!Matrix.Equals(FMatrix::Identity)) { Matrix.RemoveScaling(); } return Matrix; }
void FSCSEditorViewportClient::ToggleIsSimulateEnabled() { // Must destroy existing actors before we toggle the world state DestroyPreview(); bIsSimulateEnabled = !bIsSimulateEnabled; PreviewScene->GetWorld()->bBegunPlay = bIsSimulateEnabled; PreviewScene->GetWorld()->bShouldSimulatePhysics = bIsSimulateEnabled; AActor* PreviewActor = GetPreviewActor(); TSharedRef<SWidget> SCSEditor = BlueprintEditorPtr.Pin()->GetSCSEditor(); TSharedRef<SWidget> Inspector = BlueprintEditorPtr.Pin()->GetInspector(); // When simulate is enabled, we don't want to allow the user to modify the components UpdatePreviewActorForBlueprint(PreviewBlueprint, true); SCSEditor->SetEnabled(!bIsSimulateEnabled); Inspector->SetEnabled(!bIsSimulateEnabled); if(!IsRealtime()) { ToggleRealtimePreview(); } }
bool FSCSEditorViewportClient::IsPreviewSceneValid() const { return GetPreviewActor() != NULL; }
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; }
void FSCSEditorViewportClient::UpdatePreviewActorForBlueprint(UBlueprint* InBlueprint, bool bInForceFullUpdate/* = false*/) { AActor* PreviewActor = GetPreviewActor(); // Signal that we're going to be constructing editor components if(InBlueprint != NULL && InBlueprint->SimpleConstructionScript != NULL) { InBlueprint->SimpleConstructionScript->BeginEditorComponentConstruction(); } // If the Blueprint is changing if(InBlueprint != PreviewBlueprint || bInForceFullUpdate) { // Destroy the previous actor instance DestroyPreview(); // Save the Blueprint we're creating a preview for PreviewBlueprint = InBlueprint; // Spawn a new preview actor based on the Blueprint's generated class if it's Actor-based if(PreviewBlueprint && PreviewBlueprint->GeneratedClass && PreviewBlueprint->GeneratedClass->IsChildOf(AActor::StaticClass())) { FVector SpawnLocation = FVector::ZeroVector; FRotator SpawnRotation = FRotator::ZeroRotator; // Spawn an Actor based on the Blueprint's generated class FActorSpawnParameters SpawnInfo; SpawnInfo.bNoCollisionFail = true; SpawnInfo.bNoFail = true; SpawnInfo.ObjectFlags = RF_Transient; // Temporarily remove the deprecated flag so we can respawn the Blueprint in the viewport bool bIsClassDeprecated = PreviewBlueprint->GeneratedClass->HasAnyClassFlags(CLASS_Deprecated); PreviewBlueprint->GeneratedClass->ClassFlags &= ~CLASS_Deprecated; PreviewActorPtr = PreviewActor = PreviewScene->GetWorld()->SpawnActor( PreviewBlueprint->GeneratedClass, &SpawnLocation, &SpawnRotation, SpawnInfo ); // Reassign the deprecated flag if it was previously assigned if(bIsClassDeprecated) { PreviewBlueprint->GeneratedClass->ClassFlags |= CLASS_Deprecated; } check(PreviewActor); // Ensure that the actor is visible if(PreviewActor->bHidden) { PreviewActor->bHidden = false; PreviewActor->MarkComponentsRenderStateDirty(); GetWorld()->SendAllEndOfFrameUpdates(); } // Prevent any audio from playing as a result of spawning if(GEngine->AudioDevice) { GEngine->AudioDevice->Flush(GetWorld()); } // Set the reference to the preview actor for component editing purposes if(PreviewBlueprint->SimpleConstructionScript != NULL) { PreviewBlueprint->SimpleConstructionScript->SetComponentEditorActorInstance(PreviewActor); } // Run the construction scripts again, otherwise the actor will appear as though it's had a script pass first, rather than the default properties as shown in the details panel PreviewActor->RerunConstructionScripts(); } } else if(PreviewActor) { PreviewActor->RerunConstructionScripts(); } // Signal that we're done constructing editor components if(InBlueprint != NULL && InBlueprint->SimpleConstructionScript != NULL) { InBlueprint->SimpleConstructionScript->EndEditorComponentConstruction(); } Invalidate(); RefreshPreviewBounds(); }
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(); if(PreviewActor) { TArray<FSCSEditorTreeNodePtrType> SelectedNodes = BlueprintEditorPtr.Pin()->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->IsRoot() && !SelectedNodePtr->IsInherited() && !IsMovableParentNodeSelected(SelectedNodePtr, SelectedNodes); if(bCanEdit) { USceneComponent* SceneComp = Cast<USceneComponent>(SelectedNodePtr->FindComponentInstanceInActor(PreviewActor, true)); USceneComponent* SelectedTemplate = Cast<USceneComponent>(SelectedNodePtr->GetComponentTemplate()); if(SceneComp != NULL && SelectedTemplate != NULL) { // Cache the current default values for propagation FVector OldRelativeLocation = SelectedTemplate->RelativeLocation; FRotator OldRelativeRotation = SelectedTemplate->RelativeRotation; FVector OldRelativeScale3D = SelectedTemplate->RelativeScale3D; USceneComponent* ParentSceneComp = SceneComp->GetAttachParent(); if( ParentSceneComp ) { const FTransform ParentToWorldSpace = ParentSceneComp->GetSocketTransform(SceneComp->AttachSocketName); if(!SceneComp->bAbsoluteLocation) { Drag = ParentToWorldSpace.Inverse().TransformVector(Drag); } if(!SceneComp->bAbsoluteRotation) { Rot = (ParentToWorldSpace.Inverse().GetRotation() * Rot.Quaternion() * ParentToWorldSpace.GetRotation()).Rotator(); } } FComponentEditorUtils::FTransformData OldDefaultTransform(*SelectedTemplate); TSharedPtr<ISCSEditorCustomization> Customization = BlueprintEditorPtr.Pin()->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); } FComponentEditorUtils::FTransformData NewDefaultTransform(*SelectedTemplate); if (SelectedNodePtr->IsNative()) { if (ensure(SelectedTemplate->HasAnyFlags(RF_DefaultSubObject))) { FComponentEditorUtils::PropagateTransformPropertyChange(SelectedTemplate, OldDefaultTransform, NewDefaultTransform, UpdatedComponents); } } 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); } // Get the Blueprint class default object AActor* CDO = NULL; if(PreviewBlueprint->GeneratedClass) { CDO = Cast<AActor>(PreviewBlueprint->GeneratedClass->ClassDefaultObject); } else if(PreviewBlueprint->ParentClass) { CDO = Cast<AActor>(PreviewBlueprint->ParentClass->ClassDefaultObject); } if(CDO != NULL) { // Iterate over all the active archetype instances and propagate the change(s) to the matching component instance TArray<UObject*> ArchetypeInstances; CDO->GetArchetypeInstances(ArchetypeInstances); for(int32 InstanceIndex = 0; InstanceIndex < ArchetypeInstances.Num(); ++InstanceIndex) { AActor* ArchetypeInstance = Cast<AActor>(ArchetypeInstances[InstanceIndex]); if(ArchetypeInstance != NULL) { const bool bIsProcessingPreviewActor = (ArchetypeInstance == PreviewActor); SceneComp = Cast<USceneComponent>(SelectedNodePtr->FindComponentInstanceInActor(ArchetypeInstance, bIsProcessingPreviewActor)); if(!bIsProcessingPreviewActor && SceneComp != nullptr && !UpdatedComponents.Contains(SceneComp)) { FComponentEditorUtils::PropagateTransformPropertyChange(SceneComp, SceneComp->RelativeLocation, OldRelativeLocation, SelectedTemplate->RelativeLocation, UpdatedComponents); FComponentEditorUtils::PropagateTransformPropertyChange(SceneComp, SceneComp->RelativeRotation, OldRelativeRotation, SelectedTemplate->RelativeRotation, UpdatedComponents); FComponentEditorUtils::PropagateTransformPropertyChange(SceneComp, SceneComp->RelativeScale3D, OldRelativeScale3D, SelectedTemplate->RelativeScale3D, UpdatedComponents); } } } } } } } } GUnrealEd->RedrawLevelEditingViewports(); } } Invalidate(); } return bHandled; }