// Copyright 1998-2014 Epic Games, Inc. All Rights Reserved. #include "DetailCustomizationsPrivatePCH.h" #include "ComponentsTree.h" #include "Editor/UnrealEd/Public/SComponentClassCombo.h" #include "Editor/UnrealEd/Public/ClassIconFinder.h" ////////////////////////////////////////////////////////////////////////// FComponentTreeNode::FComponentTreeNode(UActorComponent* InComponent) { Component = InComponent; USceneComponent* SceneComp = Cast(InComponent); if(SceneComp != NULL) { for(int32 ChildIdx=0; ChildIdxAttachChildren.Num(); ChildIdx++) { USceneComponent* ChildComp = SceneComp->AttachChildren[ChildIdx]; if(ChildComp && !ChildComp->IsPendingKill()) { FComponentTreeNodePtrType ChildNode = MakeShareable(new FComponentTreeNode(ChildComp)); ChildNodes.Add(ChildNode); } } } } ////////////////////////////////////////////////////////////////////////// void SComponentRowWidget::Construct( const FArguments& InArgs, FComponentTreeNodePtrType InNodePtr ) { NodePtr = InNodePtr; FString ComponentName; const FSlateBrush* ComponentIcon = FEditorStyle::GetBrush("SCS.NativeComponent"); FSlateColor ComponentColor = FLinearColor::White; TSharedPtr Node = NodePtr.Pin(); if(Node.IsValid() && Node->Component.IsValid()) { ComponentName = Node->Component->GetName(); ComponentIcon = FClassIconFinder::FindIconForClass( Node->Component->GetClass(), TEXT("SCS.Component") ); // Color native and BP-made components in different colors if(Node->Component->IsDefaultSubobject()) { ComponentColor = FLinearColor(0.08f,0.15f,0.6f); } else if(Node->Component->bCreatedByConstructionScript) { ComponentColor = FLinearColor(0.08f,0.35f,0.6f); } } this->ChildSlot [ SNew(SHorizontalBox) +SHorizontalBox::Slot() .AutoWidth() .VAlign(VAlign_Center) [ SNew(SImage) .Image(ComponentIcon) .ColorAndOpacity(ComponentColor) ] +SHorizontalBox::Slot() .AutoWidth() .VAlign(VAlign_Center) .Padding(4,0,4,0) [ SNew(STextBlock) .Text(ComponentName) ] ]; } ////////////////////////////////////////////////////////////////////////// // Don't show any 'disable on instance' properties, these are instances of components we are seeing static bool IsPropertyVisible( const UProperty* InProperty ) { if ((InProperty != NULL) && InProperty->HasAllPropertyFlags(CPF_DisableEditOnInstance)) { return false; } return true; } void SComponentsTree::Construct( const FArguments& InArgs, AActor* InActor ) { Actor = InActor; FPropertyEditorModule& EditModule = FModuleManager::Get().GetModuleChecked("PropertyEditor"); FDetailsViewArgs DetailsViewArgs( /*bUpdateFromSelection=*/ false, /*bLockable=*/ false, /*bAllowSearch=*/ true, /*bObjectsUseNameArea=*/ true, /*bHideSelectionTip=*/ true ); DetailsViewArgs.bHideActorNameArea = true; PropertyView = EditModule.CreateDetailView( DetailsViewArgs ); // Setup delegate to hide 'edit default only' properties PropertyView->SetIsPropertyVisibleDelegate( FIsPropertyVisible::CreateStatic(&IsPropertyVisible) ); this->ChildSlot [ SNew(SBorder) .Padding( 2 ) .BorderImage( FEditorStyle::GetBrush("ToolPanel.GroupBorder") ) .Content() [ SNew(SVerticalBox) +SVerticalBox::Slot() .AutoHeight() [ SAssignNew(TreeWidget, SComponentTreeType) .TreeItemsSource( &RootNodes ) .OnGenerateRow( this, &SComponentsTree::MakeTableRowWidget ) .OnGetChildren( this, &SComponentsTree::OnGetChildrenForTree ) .OnSelectionChanged( this, &SComponentsTree::OnTreeSelectionChanged ) .ItemHeight( 24 ) ] +SVerticalBox::Slot() .AutoHeight() .Padding(0.f, 2.f, 0.f, 0.f) [ SNew(SComponentClassCombo) .OnComponentClassSelected(this, &SComponentsTree::OnSelectedCompClass) ] +SVerticalBox::Slot() .Padding(0.f, 2.f, 0.f, 0.f) .AutoHeight() [ PropertyView.ToSharedRef() ] ] ]; UpdateTree(); } TSharedRef SComponentsTree::MakeTableRowWidget( FComponentTreeNodePtrType InNodePtr, const TSharedRef& OwnerTable ) { return SNew(STableRow, OwnerTable) [ SNew(SComponentRowWidget, InNodePtr) ]; } void SComponentsTree::OnGetChildrenForTree( FComponentTreeNodePtrType InNodePtr, TArray& OutChildren ) { if(InNodePtr.IsValid()) { OutChildren = InNodePtr->ChildNodes; } } void SComponentsTree::OnTreeSelectionChanged(FComponentTreeNodePtrType InSelectedNodePtr, ESelectInfo::Type SelectInfo) { if(InSelectedNodePtr.IsValid() && InSelectedNodePtr->Component.IsValid()) { TArray Objects; Objects.Add(InSelectedNodePtr->Component.Get()); PropertyView->SetObjects(Objects, false); } } void SComponentsTree::OnSelectedCompClass(TSubclassOf CompClass) { if(Actor.IsValid()) { // Create new component UActorComponent* NewComp = NewObject(Actor.Get(), CompClass); check(NewComp); // Add to SerializedComponents array so it gets saved Actor->SerializedComponents.Add(NewComp); // If a scene component, and actor has a root component, attach it to root USceneComponent* NewSceneComp = Cast(NewComp); USceneComponent* RootComp = Actor->GetRootComponent(); if(NewSceneComp && RootComp) { NewSceneComp->AttachTo(RootComp); } // Register component NewSceneComp->RegisterComponent(); // Update tree to see result UpdateTree(); } } void SComponentsTree::UpdateTree() { check(TreeWidget.IsValid()); RootNodes.Empty(); if(Actor.IsValid()) { // Add root component (which will add its children) USceneComponent* RootComp = Actor->GetRootComponent(); if(RootComp && !RootComp->IsPendingKill()) { FComponentTreeNodePtrType RootNode = MakeShareable(new FComponentTreeNode(RootComp)); RootNodes.Add(RootNode); } // Add non-scene components in Components array TArray Components; Actor->GetComponents(Components); for(int32 CompIdx=0; CompIdxIsA(USceneComponent::StaticClass()) && !Comp->IsPendingKill()) { FComponentTreeNodePtrType Node = MakeShareable(new FComponentTreeNode(Comp)); RootNodes.Add(Node); } } } // refresh widget TreeWidget->RequestTreeRefresh(); }