void UUnrealEdEngine::DrawComponentVisualizersHUD(const FViewport* Viewport, const FSceneView* View, FCanvas* Canvas) { // Iterate over all selected actors for (FSelectionIterator It(GetSelectedActorIterator()); It; ++It) { AActor* Actor = Cast<AActor>(*It); if (Actor != NULL) { // Then iterate over components of that actor TInlineComponentArray<UActorComponent*> Components; Actor->GetComponents(Components); for (int32 CompIdx = 0; CompIdx<Components.Num(); CompIdx++) { UActorComponent* Comp = Components[CompIdx]; if (Comp->IsRegistered()) { // Try and find a visualizer TSharedPtr<FComponentVisualizer> Visualizer = FindComponentVisualizer(Comp->GetClass()); if (Visualizer.IsValid()) { Visualizer->DrawVisualizationHUD(Comp, Viewport, View, Canvas); } } } } } }
void EmitProperties(FEmitterLocalContext& Context) { ensure(!NativeVariablePropertyName.IsEmpty()); if (bSetNativeCreationMethod) { Context.AddLine(FString::Printf(TEXT("%s->CreationMethod = EComponentCreationMethod::Native;"), *NativeVariablePropertyName)); } if (!ParentVariableName.IsEmpty()) { const FString SocketName = (AttachToName == NAME_None) ? FString() : FString::Printf(TEXT(", TEXT(\"%s\")"), *AttachToName.ToString()); Context.AddLine(FString::Printf(TEXT("%s->AttachTo(%s %s);"), *NativeVariablePropertyName, *ParentVariableName, *SocketName)); // AttachTo is called first in case some properties will be overridden. } UClass* ComponentClass = ComponentTemplate->GetClass(); for (auto Property : TFieldRange<const UProperty>(ComponentClass)) { FEmitDefaultValueHelper::OuterGenerate(Context, Property, NativeVariablePropertyName , reinterpret_cast<const uint8*>(ComponentTemplate) , reinterpret_cast<const uint8*>(ObjectToCompare) , FEmitDefaultValueHelper::EPropertyAccessOperator::Pointer); } }
void UComponentDelegateBinding::BindDynamicDelegates(AActor* InInstance) const { for(int32 BindIdx=0; BindIdx<ComponentDelegateBindings.Num(); BindIdx++) { const FBlueprintComponentDelegateBinding& Binding = ComponentDelegateBindings[BindIdx]; // Get the function we want to bind UFunction* FunctionToBind = FindField<UFunction>(InInstance->GetClass(), Binding.FunctionNameToBind); // Get the property that points to the component we want to assign to UObjectProperty* ObjProp = FindField<UObjectProperty>(InInstance->GetClass(), Binding.ComponentPropertyName); // If we have both of those.. if(ObjProp != NULL && FunctionToBind != NULL) { // ..see if there is actually a component assigned UActorComponent* Component = Cast<UActorComponent>(ObjProp->GetObjectPropertyValue_InContainer(InInstance)); if(Component != NULL) { // If there is, find the delegate property on it UMulticastDelegateProperty* DelegateProp = FindField<UMulticastDelegateProperty>(Component->GetClass(), Binding.DelegatePropertyName); if(DelegateProp) { // Found that, finally bind function on the actor to this delegate FMulticastScriptDelegate* TargetDelegate = DelegateProp->GetPropertyValuePtr_InContainer(Component); FScriptDelegate Delegate; Delegate.SetFunctionName(Binding.FunctionNameToBind); Delegate.SetObject(InInstance); TargetDelegate->AddUnique(Delegate); } } } } }
void SGraphPinLiveEditVar::GenerateComboBoxIndexes( TArray< TSharedPtr<int32> >& OutComboBoxIndexes ) { if ( !NodeClass.IsValid() ) return; UClass *InClass = Cast<UClass>(NodeClass.Get()); if ( InClass == NULL ) return; GenerateComboBoxIndexesRecurse( InClass, FString(TEXT("")), OutComboBoxIndexes ); AActor *AsActor = Cast<AActor>(InClass->ClassDefaultObject); if ( AsActor != NULL ) { TArray<UActorComponent*> ActorComponents; AsActor->GetComponents(ActorComponents); for ( TArray<UActorComponent*>::TIterator ComponentIt(ActorComponents); ComponentIt; ++ComponentIt ) { UActorComponent *Component = *ComponentIt; check( Component != NULL ); FString ComponentName = Component->GetName() + FString(TEXT(".")); GenerateComboBoxIndexesRecurse( Component->GetClass(), ComponentName, OutComboBoxIndexes ); } } for (int32 i = 0; i < VariableNameList.Num(); ++i) { TSharedPtr<int32> EnumIdxPtr(new int32(i)); OutComboBoxIndexes.Add(EnumIdxPtr); } }
void UK2Node_AddComponent::ValidateNodeDuringCompilation(FCompilerResultsLog& MessageLog) const { Super::ValidateNodeDuringCompilation(MessageLog); UActorComponent* Template = GetTemplateFromNode(); if (Template) { UClass* TemplateClass = Template->GetClass(); if (!TemplateClass->IsChildOf(UActorComponent::StaticClass()) || TemplateClass->HasAnyClassFlags(CLASS_Abstract) || !TemplateClass->HasMetaData(FBlueprintMetadata::MD_BlueprintSpawnableComponent) ) { FFormatNamedArguments Args; Args.Add(TEXT("TemplateClass"), FText::FromString(TemplateClass->GetName())); Args.Add(TEXT("NodeTitle"), GetNodeTitle(ENodeTitleType::FullTitle)); MessageLog.Error(*FText::Format(NSLOCTEXT("KismetCompiler", "InvalidComponentTemplate_Error", "Invalid class '{TemplateClass}' used as template by '{NodeTitle}' for @@"), Args).ToString(), this); } if (UChildActorComponent const* ChildActorComponent = Cast<UChildActorComponent const>(Template)) { UBlueprint const* Blueprint = GetBlueprint(); UClass const* ChildActorClass = ChildActorComponent->GetChildActorClass(); if (ChildActorClass == Blueprint->GeneratedClass) { UEdGraph const* ParentGraph = GetGraph(); UEdGraphSchema_K2 const* K2Schema = GetDefault<UEdGraphSchema_K2>(); if (K2Schema->IsConstructionScript(ParentGraph)) { FFormatNamedArguments Args; Args.Add(TEXT("ChildActorClass"), FText::FromString(ChildActorClass->GetName())); MessageLog.Error(*FText::Format(NSLOCTEXT("KismetCompiler", "AddSelfComponent_Error", "@@ cannot add a '{ChildActorClass}' component in the construction script (could cause infinite recursion)."), Args).ToString(), this); } } else if (ChildActorClass != nullptr) { AActor const* ChildActor = Cast<AActor>(ChildActorClass->ClassDefaultObject); check(ChildActor != nullptr); USceneComponent* RootComponent = ChildActor->GetRootComponent(); if ((RootComponent != nullptr) && (RootComponent->Mobility == EComponentMobility::Static) && (ChildActorComponent->Mobility != EComponentMobility::Static)) { FFormatNamedArguments Args; Args.Add(TEXT("ChildActorClass"), FText::FromString(ChildActorClass->GetName())); MessageLog.Error(*FText::Format(NSLOCTEXT("KismetCompiler", "AddStaticChildActorComponent_Error", "@@ cannot add a '{ChildActorClass}' component as it has static mobility, and the ChildActorComponent does not."), Args).ToString(), this); } } } } else { FFormatNamedArguments Args; Args.Add(TEXT("NodeTitle"), GetNodeTitle(ENodeTitleType::FullTitle)); MessageLog.Error(*FText::Format(NSLOCTEXT("KismetCompiler", "MissingComponentTemplate_Error", "Unknown template referenced by '{NodeTitle}' for @@"), Args).ToString(), this); } }
static UProperty *GetPropertyByName( UClass *InClass, const FName &Name ) { if ( InClass == NULL ) return NULL; UProperty *Property = GetPropertyByNameRecurse( InClass, Name.ToString() ); if ( Property != NULL ) { return Property; } AActor *AsActor = Cast<AActor>(InClass->ClassDefaultObject); if ( AsActor != NULL ) { FString ComponentPropertyName = Name.ToString(); int32 SplitIndex = 0; if ( ComponentPropertyName.FindChar( '.', SplitIndex ) ) { //FString ComponentName = ComponentPropertyName.LeftChop(SplitIndex); ComponentPropertyName = ComponentPropertyName.RightChop(SplitIndex+1); TInlineComponentArray<UActorComponent*> ActorComponents; AsActor->GetComponents(ActorComponents); for ( auto ComponentIt = ActorComponents.CreateIterator(); ComponentIt; ++ComponentIt ) { UActorComponent *Component = *ComponentIt; check( Component != NULL ); /* if ( Component->GetName() != ComponentName ) { continue; } */ Property = GetPropertyByNameRecurse( Component->GetClass(), ComponentPropertyName ); if ( Property != NULL ) { return Property; } } } } return NULL; }
FString UK2Node_AddComponent::GetDocumentationExcerptName() const { UEdGraphPin* TemplateNamePin = GetTemplateNamePin(); UBlueprint* Blueprint = GetBlueprint(); if ((TemplateNamePin != NULL) && (Blueprint != NULL)) { FString TemplateName = TemplateNamePin->DefaultValue; UActorComponent* SourceTemplate = Blueprint->FindTemplateByName(FName(*TemplateName)); if (SourceTemplate != NULL) { return SourceTemplate->GetClass()->GetName(); } } return Super::GetDocumentationExcerptName(); }
static UProperty *GetPropertyByName( UObject *Target, UStruct *InStruct, const FString &PropertyName, void ** hContainerPtr, int32 &OutArrayIndex ) { UProperty *Prop = GetPropertyByNameRecurse( Target->GetClass(), PropertyName, hContainerPtr, OutArrayIndex ); if ( Prop == NULL ) { AActor *AsActor = Cast<AActor>(Target); if ( AsActor != NULL ) { FString ComponentPropertyName = PropertyName; int32 SplitIndex = 0; if ( ComponentPropertyName.FindChar( '.', SplitIndex ) ) { //FString ComponentName = ComponentPropertyName.LeftChop(SplitIndex); ComponentPropertyName = ComponentPropertyName.RightChop(SplitIndex+1); TArray<UActorComponent*> ActorComponents; AsActor->GetComponents(ActorComponents); for ( TArray<UActorComponent*>::TIterator ComponentIt(ActorComponents); ComponentIt && !Prop; ++ComponentIt ) { UActorComponent *Component = *ComponentIt; check( Component != NULL ); /* if ( Component->GetName() != ComponentName ) { continue; } */ *hContainerPtr = Component; Prop = GetPropertyByNameRecurse( Component->GetClass(), ComponentPropertyName, hContainerPtr, OutArrayIndex ); } } } } return Prop; }
bool FComponentEditorUtils::CanCopyComponents(const TArray<UActorComponent*>& ComponentsToCopy) { bool bCanCopy = ComponentsToCopy.Num() > 0; if (bCanCopy) { for (int32 i = 0; i < ComponentsToCopy.Num() && bCanCopy; ++i) { // Check for the default scene root; that cannot be copied/duplicated UActorComponent* Component = ComponentsToCopy[i]; bCanCopy = Component != nullptr && Component->GetFName() != USceneComponent::GetDefaultSceneRootVariableName(); if (bCanCopy) { UClass* ComponentClass = Component->GetClass(); check(ComponentClass != nullptr); // Component class cannot be abstract and must also be tagged as BlueprintSpawnable bCanCopy = !ComponentClass->HasAnyClassFlags(CLASS_Abstract) && ComponentClass->HasMetaData(FBlueprintMetadata::MD_BlueprintSpawnableComponent); } } } return bCanCopy; }
void UK2Node_AddComponent::PostPasteNode() { Super::PostPasteNode(); // There is a template associated with this node that should be unique, but after a node is pasted, it either points to a // template shared by the copied node, or to nothing (when pasting into a different blueprint) const UEdGraphSchema_K2* K2Schema = GetDefault<UEdGraphSchema_K2>(); UBlueprint* Blueprint = GetBlueprint(); // Find the template name and return type pins UEdGraphPin* TemplateNamePin = GetTemplateNamePin(); UEdGraphPin* ReturnPin = GetReturnValuePin(); if ((TemplateNamePin != NULL) && (ReturnPin != NULL)) { // Find the current template if it exists FString TemplateName = TemplateNamePin->DefaultValue; UActorComponent* SourceTemplate = Blueprint->FindTemplateByName(FName(*TemplateName)); // Determine the type of the component needed UClass* ComponentClass = Cast<UClass>(ReturnPin->PinType.PinSubCategoryObject.Get()); if (ComponentClass) { ensure(NULL != Cast<UBlueprintGeneratedClass>(Blueprint->GeneratedClass)); // Create a new template object and update the template pin to point to it UActorComponent* NewTemplate = NewObject<UActorComponent>(Blueprint->GeneratedClass, ComponentClass, NAME_None, RF_ArchetypeObject|RF_Public); Blueprint->ComponentTemplates.Add(NewTemplate); TemplateNamePin->DefaultValue = NewTemplate->GetName(); // Copy the old template data over to the new template if it's compatible if ((SourceTemplate != NULL) && (SourceTemplate->GetClass()->IsChildOf(ComponentClass))) { TArray<uint8> SavedProperties; FObjectWriter Writer(SourceTemplate, SavedProperties); FObjectReader(NewTemplate, SavedProperties); } else if(TemplateBlueprint.Len() > 0) { // try to find/load our blueprint to copy the template UBlueprint* SourceBlueprint = FindObject<UBlueprint>(NULL, *TemplateBlueprint); if(SourceBlueprint != NULL) { SourceTemplate = SourceBlueprint->FindTemplateByName(FName(*TemplateName)); if ((SourceTemplate != NULL) && (SourceTemplate->GetClass()->IsChildOf(ComponentClass))) { TArray<uint8> SavedProperties; FObjectWriter Writer(SourceTemplate, SavedProperties); FObjectReader(NewTemplate, SavedProperties); } } TemplateBlueprint.Empty(); } } else { // Clear the template connection; can't resolve the type of the component to create ensure(false); TemplateNamePin->DefaultValue = TEXT(""); } } }
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::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 FComponentMaterialCategory::OnMaterialChanged( UMaterialInterface* NewMaterial, UMaterialInterface* PrevMaterial, int32 SlotIndex, bool bReplaceAll ) { // Whether or not we should begin a transaction on swap // Note we only begin a transaction on the first swap bool bShouldMakeTransaction = true; // Whether or not we made a transaction and need to end it bool bMadeTransaction = false; // Lambda to swap materials on a given component at the given slot index auto SwapMaterialLambda = []( UActorComponent* InComponent, int32 InElementIndex, UMaterialInterface* InNewMaterial ) { UPrimitiveComponent* PrimitiveComp = Cast<UPrimitiveComponent>( InComponent ); UDecalComponent* DecalComponent = Cast<UDecalComponent>( InComponent ); if( PrimitiveComp ) { PrimitiveComp->SetMaterial( InElementIndex, InNewMaterial ); } else if( DecalComponent ) { DecalComponent->SetMaterial( InElementIndex, InNewMaterial ); } }; // Scan the selected actors mesh components for the old material and swap it with the new material for( FMaterialIterator It( SelectedComponents ); It; ++It ) { int32 MaterialIndex = It.GetMaterialIndex(); UActorComponent* CurrentComponent = It.GetComponent(); if( CurrentComponent ) { // Component materials can be replaced if they are not created from a blueprint (not exposed to the user) and have material overrides on the component bool bCanBeReplaced = ( CurrentComponent->IsA( UMeshComponent::StaticClass() ) || CurrentComponent->IsA( UDecalComponent::StaticClass() ) || CurrentComponent->IsA( UTextRenderComponent::StaticClass() ) || CurrentComponent->IsA( ULandscapeComponent::StaticClass() ) ); UMaterialInterface* Material = It.GetMaterial(); // Check if the material is the same as the previous material or we are replaceing all in the same slot. If so we will swap it with the new material if( bCanBeReplaced && ( Material == PrevMaterial || bReplaceAll ) && It.GetMaterialIndex() == SlotIndex ) { // Begin a transaction for undo/redo the first time we encounter a material to replace. // There is only one transaction for all replacement if( bShouldMakeTransaction && !bMadeTransaction ) { GEditor->BeginTransaction( NSLOCTEXT("UnrealEd", "ReplaceComponentUsedMaterial", "Replace component used material") ); bMadeTransaction = true; } UProperty* MaterialProperty = NULL; UObject* EditChangeObject = CurrentComponent; if( CurrentComponent->IsA( UMeshComponent::StaticClass() ) ) { MaterialProperty = FindField<UProperty>( UMeshComponent::StaticClass(), "OverrideMaterials" ); } else if( CurrentComponent->IsA( UDecalComponent::StaticClass() ) ) { MaterialProperty = FindField<UProperty>( UDecalComponent::StaticClass(), "DecalMaterial" ); } else if( CurrentComponent->IsA( UTextRenderComponent::StaticClass() ) ) { MaterialProperty = FindField<UProperty>( UTextRenderComponent::StaticClass(), "TextMaterial" ); } else if (CurrentComponent->IsA<ULandscapeComponent>() ) { MaterialProperty = FindField<UProperty>( ALandscapeProxy::StaticClass(), "LandscapeMaterial" ); EditChangeObject = CastChecked<ULandscapeComponent>(CurrentComponent)->GetLandscapeProxy(); } // Add a navigation update lock only if the component world is valid TSharedPtr<FNavigationLockContext> NavUpdateLock; UWorld* World = CurrentComponent->GetWorld(); if( World ) { NavUpdateLock = MakeShareable( new FNavigationLockContext(World, ENavigationLockReason::MaterialUpdate) ); } EditChangeObject->PreEditChange( MaterialProperty ); if( NotifyHook && MaterialProperty ) { NotifyHook->NotifyPreChange( MaterialProperty ); } SwapMaterialLambda( CurrentComponent, It.GetMaterialIndex(), NewMaterial ); FPropertyChangedEvent PropertyChangedEvent( MaterialProperty ); EditChangeObject->PostEditChangeProperty( PropertyChangedEvent ); if( NotifyHook && MaterialProperty ) { NotifyHook->NotifyPostChange( PropertyChangedEvent, MaterialProperty ); } // Propagate material change to instances of the edited component template if( !FApp::IsGame() ) { TArray<UObject*> ComponentArchetypeInstances; if( CurrentComponent->HasAnyFlags(RF_ArchetypeObject) ) { CurrentComponent->GetArchetypeInstances(ComponentArchetypeInstances); } else if( UObject* Outer = CurrentComponent->GetOuter() ) { TArray<UObject*> OuterArchetypeInstances; Outer->GetArchetypeInstances(OuterArchetypeInstances); for( auto OuterArchetypeInstance : OuterArchetypeInstances ) { if( UObject* ArchetypeInstance = static_cast<UObject*>(FindObjectWithOuter(OuterArchetypeInstance, CurrentComponent->GetClass(), CurrentComponent->GetFName())) ) { ComponentArchetypeInstances.Add(ArchetypeInstance); } } } for( auto ComponentArchetypeInstance : ComponentArchetypeInstances ) { CurrentComponent = CastChecked<UActorComponent>( ComponentArchetypeInstance ); if( CurrentComponent->IsA<ULandscapeComponent>() ) { ComponentArchetypeInstance = CastChecked<ULandscapeComponent>(CurrentComponent)->GetLandscapeProxy(); } // Reset the navigation update lock if necessary UWorld* PreviousWorld = World; World = CurrentComponent->GetWorld(); if( PreviousWorld != World ) { NavUpdateLock = MakeShareable( new FNavigationLockContext(World, ENavigationLockReason::MaterialUpdate) ); } ComponentArchetypeInstance->PreEditChange( MaterialProperty ); SwapMaterialLambda( CurrentComponent, It.GetMaterialIndex(), NewMaterial ); ComponentArchetypeInstance->PostEditChangeProperty( PropertyChangedEvent ); } } } } } if( bMadeTransaction ) { // End the transation if we created one GEditor->EndTransaction(); // Redraw viewports to reflect the material changes GUnrealEd->RedrawLevelEditingViewports(); } }
void FComponentEditorUtils::FillComponentContextMenuOptions(FMenuBuilder& MenuBuilder, const TArray<UActorComponent*>& SelectedComponents) { // Basic commands MenuBuilder.BeginSection("EditComponent", LOCTEXT("EditComponentHeading", "Edit")); { MenuBuilder.AddMenuEntry(FGenericCommands::Get().Cut); MenuBuilder.AddMenuEntry(FGenericCommands::Get().Copy); MenuBuilder.AddMenuEntry(FGenericCommands::Get().Paste); MenuBuilder.AddMenuEntry(FGenericCommands::Get().Duplicate); MenuBuilder.AddMenuEntry(FGenericCommands::Get().Delete); MenuBuilder.AddMenuEntry(FGenericCommands::Get().Rename); } MenuBuilder.EndSection(); if (SelectedComponents.Num() == 1) { UActorComponent* Component = SelectedComponents[0]; if (Component->GetClass()->ClassGeneratedBy) { MenuBuilder.BeginSection("ComponentAsset", LOCTEXT("ComponentAssetHeading", "Asset")); { MenuBuilder.AddMenuEntry( FText::Format(LOCTEXT("GoToBlueprintForComponent", "Edit {0}"), FText::FromString(Component->GetClass()->ClassGeneratedBy->GetName())), LOCTEXT("EditBlueprintForComponent_ToolTip", "Edits the Blueprint Class that defines this component."), FSlateIcon(FEditorStyle::GetStyleSetName(), FClassIconFinder::FindIconNameForClass(Component->GetClass())), FUIAction( FExecuteAction::CreateStatic(&FComponentEditorUtils::OnEditBlueprintComponent, Component->GetClass()->ClassGeneratedBy), FCanExecuteAction())); MenuBuilder.AddMenuEntry( LOCTEXT("GoToAssetForComponent", "Find Class in Content Browser"), LOCTEXT("GoToAssetForComponent_ToolTip", "Summons the content browser and goes to the class for this component."), FSlateIcon(FEditorStyle::GetStyleSetName(), "SystemWideCommands.FindInContentBrowser"), FUIAction( FExecuteAction::CreateStatic(&FComponentEditorUtils::OnGoToComponentAssetInBrowser, Component->GetClass()->ClassGeneratedBy), FCanExecuteAction())); } MenuBuilder.EndSection(); } else { MenuBuilder.BeginSection("ComponentCode", LOCTEXT("ComponentCodeHeading", "C++")); { if (FSourceCodeNavigation::IsCompilerAvailable()) { FString ClassHeaderPath; if (FSourceCodeNavigation::FindClassHeaderPath(Component->GetClass(), ClassHeaderPath) && IFileManager::Get().FileSize(*ClassHeaderPath) != INDEX_NONE) { const FString CodeFileName = FPaths::GetCleanFilename(*ClassHeaderPath); MenuBuilder.AddMenuEntry( FText::Format(LOCTEXT("GoToCodeForComponent", "Open {0}"), FText::FromString(CodeFileName)), FText::Format(LOCTEXT("GoToCodeForComponent_ToolTip", "Opens the header file for this component ({0}) in a code editing program"), FText::FromString(CodeFileName)), FSlateIcon(), FUIAction( FExecuteAction::CreateStatic(&FComponentEditorUtils::OnOpenComponentCodeFile, ClassHeaderPath), FCanExecuteAction())); } MenuBuilder.AddMenuEntry( LOCTEXT("GoToAssetForComponent", "Find Class in Content Browser"), LOCTEXT("GoToAssetForComponent_ToolTip", "Summons the content browser and goes to the class for this component."), FSlateIcon(FEditorStyle::GetStyleSetName(), "SystemWideCommands.FindInContentBrowser"), FUIAction( FExecuteAction::CreateStatic(&FComponentEditorUtils::OnGoToComponentAssetInBrowser, (UObject*)Component->GetClass()), FCanExecuteAction())); } } MenuBuilder.EndSection(); } } }
void FComponentEditorUtils::PasteComponents(TArray<UActorComponent*>& OutPastedComponents, AActor* TargetActor, USceneComponent* TargetComponent) { check(TargetActor); // Get the text from the clipboard FString TextToImport; FPlatformMisc::ClipboardPaste(TextToImport); // Get a new component object factory for the clipboard content TSharedRef<FComponentObjectTextFactory> Factory = FComponentObjectTextFactory::Get(TextToImport); TargetActor->Modify(); USceneComponent* TargetParent = TargetComponent ? TargetComponent->GetAttachParent() : nullptr; for (auto& NewObjectPair : Factory->NewObjectMap) { // Get the component object instance UActorComponent* NewActorComponent = NewObjectPair.Value; check(NewActorComponent); // Relocate the instance from the transient package to the Actor and assign it a unique object name FString NewComponentName = FComponentEditorUtils::GenerateValidVariableName(NewActorComponent->GetClass(), TargetActor); NewActorComponent->Rename(*NewComponentName, TargetActor, REN_DontCreateRedirectors | REN_DoNotDirty); if (auto NewSceneComponent = Cast<USceneComponent>(NewActorComponent)) { // Default to attaching to the target component's parent if possible, otherwise attach to the root USceneComponent* NewComponentParent = TargetParent ? TargetParent : TargetActor->GetRootComponent(); // Check to see if there's an entry for the current component in the set of parent components if (Factory->ParentMap.Contains(NewObjectPair.Key)) { // Get the parent component name FName ParentName = Factory->ParentMap[NewObjectPair.Key]; if (Factory->NewObjectMap.Contains(ParentName)) { // The parent should by definition be a scene component NewComponentParent = CastChecked<USceneComponent>(Factory->NewObjectMap[ParentName]); } } //@todo: Fix pasting when the pasted component was a root //NewSceneComponent->UpdateComponentToWorld(); if (NewComponentParent) { // Reattach the current node to the parent node NewSceneComponent->AttachTo(NewComponentParent, NAME_None/*, EAttachLocation::KeepWorldPosition*/); } else { // There is no root component and this component isn't the child of another component in the map, so make it the root TargetActor->SetRootComponent(NewSceneComponent); } } TargetActor->AddInstanceComponent(NewActorComponent); NewActorComponent->RegisterComponent(); OutPastedComponents.Add(NewActorComponent); } // Rerun construction scripts TargetActor->RerunConstructionScripts(); }
void SKismetInspector::UpdateFromObjects(const TArray<UObject*>& PropertyObjects, struct FKismetSelectionInfo& SelectionInfo, const FShowDetailsOptions& Options) { // If we're using the unified blueprint editor, there's not an explicit point where // we ender a kind of component editing mode, so instead, just look at what we're selecting. // If we select a component, then enable the customization. if ( GetDefault<UEditorExperimentalSettings>()->bUnifiedBlueprintEditor ) { bool bEnableComponentCustomization = false; TSharedPtr<FBlueprintEditor> BlueprintEditor = BlueprintEditorPtr.Pin(); if ( BlueprintEditor.IsValid() ) { if ( BlueprintEditor->CanAccessComponentsMode() ) { for ( UObject* PropertyObject : PropertyObjects ) { if ( PropertyObject->IsA<UActorComponent>() ) { bEnableComponentCustomization = true; break; } } } } EnableComponentDetailsCustomization(bEnableComponentCustomization); } PropertyView->OnFinishedChangingProperties().Clear(); PropertyView->OnFinishedChangingProperties().Add( UserOnFinishedChangingProperties ); if (!Options.bForceRefresh) { // Early out if the PropertyObjects and the SelectedObjects are the same bool bEquivalentSets = (PropertyObjects.Num() == SelectedObjects.Num()); if (bEquivalentSets) { // Verify the elements of the sets are equivalent for (int32 i = 0; i < PropertyObjects.Num(); i++) { if (PropertyObjects[i] != SelectedObjects[i].Get()) { bEquivalentSets = false; break; } } } if (bEquivalentSets) { return; } } // Proceed to update SelectedObjects.Empty(); for (auto ObjectIt = PropertyObjects.CreateConstIterator(); ObjectIt; ++ObjectIt) { if (UObject* Object = *ObjectIt) { if (!Object->IsValidLowLevel()) { ensureMsg(false, TEXT("Object in KismetInspector is invalid, see TTP 281915")); continue; } SelectedObjects.Add(Object); if (USCS_Node* SCSNode = Cast<USCS_Node>(Object)) { // Edit the component template UActorComponent* NodeComponent = SCSNode->ComponentTemplate; if (NodeComponent != NULL) { SelectionInfo.ObjectsForPropertyEditing.Add(NodeComponent); SelectionInfo.EditableComponentTemplates.Add(NodeComponent); } } else if (UK2Node* K2Node = Cast<UK2Node>(Object)) { // Edit the component template if it exists if (UActorComponent* Template = K2Node->GetTemplateFromNode()) { SelectionInfo.ObjectsForPropertyEditing.Add(Template); SelectionInfo.EditableComponentTemplates.Add(Template); } // See if we should edit properties of the node if (K2Node->ShouldShowNodeProperties()) { SelectionInfo.ObjectsForPropertyEditing.Add(Object); } } else if (UActorComponent* ActorComponent = Cast<UActorComponent>(Object)) { AActor* Owner = ActorComponent->GetOwner(); if(Owner != NULL && Owner->HasAnyFlags(RF_ClassDefaultObject)) { // We're editing a component that's owned by a CDO, so set the CDO to the property editor (so that propagation works) and then filter to just the component property that we want to edit SelectionInfo.ObjectsForPropertyEditing.AddUnique(Owner); SelectionInfo.EditableComponentTemplates.Add(ActorComponent); } else { // We're editing a component that exists outside of a CDO, so just edit the component instance directly SelectionInfo.ObjectsForPropertyEditing.AddUnique(ActorComponent); } } else { // Editing any UObject* SelectionInfo.ObjectsForPropertyEditing.AddUnique(Object); } } } // By default, no property filtering SelectedObjectProperties.Empty(); // Add to the property filter list for any editable component templates if(SelectionInfo.EditableComponentTemplates.Num()) { for(auto CompIt = SelectionInfo.EditableComponentTemplates.CreateIterator(); CompIt; ++CompIt) { UActorComponent* EditableComponentTemplate = *CompIt; check(EditableComponentTemplate != NULL); // Add all properties belonging to the component template class for(TFieldIterator<UProperty> PropIt(EditableComponentTemplate->GetClass()); PropIt; ++PropIt) { UProperty* Property = *PropIt; check(Property != NULL); AddPropertiesRecursive(Property); } // Attempt to locate a matching property for the current component template for(auto ObjIt = SelectionInfo.ObjectsForPropertyEditing.CreateIterator(); ObjIt; ++ObjIt) { UObject* Object = *ObjIt; check(Object != NULL); if(Object != EditableComponentTemplate) { for(TFieldIterator<UObjectProperty> ObjPropIt(Object->GetClass()); ObjPropIt; ++ObjPropIt) { UObjectProperty* ObjectProperty = *ObjPropIt; check(ObjectProperty != NULL); // If the property value matches the current component template, add it as a selected property for filtering if(EditableComponentTemplate == ObjectProperty->GetObjectPropertyValue_InContainer(Object)) { SelectedObjectProperties.Add(ObjectProperty); } } } } } } PropertyViewTitle = Options.ForcedTitle; bShowComponents = Options.bShowComponents; // Update our context-sensitive editing widget ContextualEditingBorderWidget->SetContent( MakeContextualEditingWidget(SelectionInfo, Options) ); }