//------------------------------------------------------------------------------ void FGraphActionNode::AddChildRecursively(TArray<FString>& CategoryStack, TSharedPtr<FGraphActionNode> NodeToAdd) { if (CategoryStack.Num() > 0) { FString CategorySection = CategoryStack[0]; CategoryStack.RemoveAt(0, 1); // make sure we don't already have a child that this can nest under TSharedPtr<FGraphActionNode> ExistingNode = FindMatchingParent(CategorySection, NodeToAdd); if (ExistingNode.IsValid()) { ExistingNode->AddChildRecursively(CategoryStack, NodeToAdd); } else { TSharedPtr<FGraphActionNode> CategoryNode = NewCategoryNode(CategorySection, NodeToAdd->Grouping, NodeToAdd->SectionID); InsertChild(CategoryNode); CategoryNode->AddChildRecursively(CategoryStack, NodeToAdd); } } else { InsertChild(NodeToAdd); } }
//------------------------------------------------------------------------------ void FGraphActionNode::AddChildRecursively(TArray<FString>& CategoryStack, TSharedPtr<FGraphActionNode> NodeToAdd) { if (NodeToAdd->SectionID != INVALID_SECTION_ID) { TSharedPtr<FGraphActionNode> FoundSectionNode; for ( TSharedPtr<FGraphActionNode> const& ChildNode : Children ) { if ( NodeToAdd->SectionID == ChildNode->SectionID && ChildNode->IsSectionHeadingNode() ) { FoundSectionNode = ChildNode; break; } } if ( FoundSectionNode.IsValid() ) { FoundSectionNode->AddChildRecursively(CategoryStack, NodeToAdd); return; } } if ( CategoryStack.Num() > 0 ) { FString CategorySection = CategoryStack[0]; CategoryStack.RemoveAt(0, 1); // make sure we don't already have a child that this can nest under TSharedPtr<FGraphActionNode> ExistingNode = FindMatchingParent(CategorySection, NodeToAdd); if ( ExistingNode.IsValid() ) { ExistingNode->AddChildRecursively(CategoryStack, NodeToAdd); } else { TSharedPtr<FGraphActionNode> CategoryNode = NewCategoryNode(CategorySection, NodeToAdd->Grouping, NodeToAdd->SectionID); InsertChild(CategoryNode); CategoryNode->AddChildRecursively(CategoryStack, NodeToAdd); } } else { InsertChild(NodeToAdd); } }
void FObjectPropertyNode::InternalInitChildNodes( FName SinglePropertyName ) { HiddenCategories.Empty(); // Assemble a list of category names by iterating over all fields of BaseClass. // build a list of classes that we need to look at TSet<UClass*> ClassesToConsider; for( int32 i = 0; i < GetNumObjects(); ++i ) { UObject* TempObject = GetUObject( i ); if( TempObject ) { ClassesToConsider.Add( TempObject->GetClass() ); } } const bool bShouldShowHiddenProperties = !!HasNodeFlags(EPropertyNodeFlags::ShouldShowHiddenProperties); const bool bShouldShowDisableEditOnInstance = !!HasNodeFlags(EPropertyNodeFlags::ShouldShowDisableEditOnInstance); TSet<FName> Categories; for( TFieldIterator<UProperty> It(BaseClass.Get()); It; ++It ) { bool bHidden = false; FName CategoryName = FObjectEditorUtils::GetCategoryFName(*It); for( UClass* Class : ClassesToConsider ) { if( FEditorCategoryUtils::IsCategoryHiddenFromClass(Class, CategoryName.ToString()) ) { HiddenCategories.Add( CategoryName ); bHidden = true; break; } } bool bMetaDataAllowVisible = true; FString MetaDataVisibilityCheckString = It->GetMetaData(TEXT("bShowOnlyWhenTrue")); if (MetaDataVisibilityCheckString.Len()) { //ensure that the metadata visibility string is actually set to true in order to show this property GConfig->GetBool(TEXT("UnrealEd.PropertyFilters"), *MetaDataVisibilityCheckString, bMetaDataAllowVisible, GEditorUserSettingsIni); } if (bMetaDataAllowVisible) { const bool bShowIfNonHiddenEditableProperty = (*It)->HasAnyPropertyFlags(CPF_Edit) && !bHidden; const bool bShowIfDisableEditOnInstance = !(*It)->HasAnyPropertyFlags(CPF_DisableEditOnInstance) || bShouldShowDisableEditOnInstance; if( bShouldShowHiddenProperties || (bShowIfNonHiddenEditableProperty && bShowIfDisableEditOnInstance) ) { Categories.Add( CategoryName ); } } } ////////////////////////////////////////// // Add the category headers and the child items that belong inside of them. // Only show category headers if this is the top level object window and the parent window allows headers. if( HasNodeFlags(EPropertyNodeFlags::ShowCategories) ) { FString CategoryDelimiterString; CategoryDelimiterString.AppendChar( FPropertyNodeConstants::CategoryDelimiterChar ); TArray< FPropertyNode* > ParentNodesToSort; for( const FName& FullCategoryPath : Categories ) { // Figure out the nesting level for this category TArray< FString > FullCategoryPathStrings; FullCategoryPath.ToString().ParseIntoArray( FullCategoryPathStrings, *CategoryDelimiterString, true ); TSharedPtr<FPropertyNode> ParentLevelNode = SharedThis(this); FString CurCategoryPathString; for( int32 PathLevelIndex = 0; PathLevelIndex < FullCategoryPathStrings.Num(); ++PathLevelIndex ) { // Build up the category path name for the current path level index if( CurCategoryPathString.Len() != 0 ) { CurCategoryPathString += FPropertyNodeConstants::CategoryDelimiterChar; } CurCategoryPathString += FullCategoryPathStrings[ PathLevelIndex ]; const FName CategoryName( *CurCategoryPathString ); // Check to see if we've already created a category at the specified path level bool bFoundMatchingCategory = false; { for( int32 CurNodeIndex = 0; CurNodeIndex < ParentLevelNode->GetNumChildNodes(); ++CurNodeIndex ) { TSharedPtr<FPropertyNode>& ChildNode = ParentLevelNode->GetChildNode( CurNodeIndex ); check( ChildNode.IsValid() ); // Is this a category node? FCategoryPropertyNode* ChildCategoryNode = ChildNode->AsCategoryNode(); if( ChildCategoryNode != NULL ) { // Does the name match? if( ChildCategoryNode->GetCategoryName() == CategoryName ) { // Descend by using the child node as the new parent bFoundMatchingCategory = true; ParentLevelNode = ChildNode; break; } } } } // If we didn't find the category, then we'll need to create it now! if( !bFoundMatchingCategory ) { // Create the category node and assign it to its parent node TSharedPtr<FCategoryPropertyNode> NewCategoryNode( new FCategoryPropertyNode ); { NewCategoryNode->SetCategoryName( CategoryName ); FPropertyNodeInitParams InitParams; InitParams.ParentNode = ParentLevelNode; InitParams.Property = NULL; InitParams.ArrayOffset = 0; InitParams.ArrayIndex = INDEX_NONE; InitParams.bAllowChildren = true; InitParams.bForceHiddenPropertyVisibility = bShouldShowHiddenProperties; InitParams.bCreateDisableEditOnInstanceNodes = bShouldShowDisableEditOnInstance; NewCategoryNode->InitNode( InitParams ); // Recursively expand category properties if the category has been flagged for auto-expansion. if (BaseClass->IsAutoExpandCategory(*CategoryName.ToString()) && !BaseClass->IsAutoCollapseCategory(*CategoryName.ToString())) { NewCategoryNode->SetNodeFlags(EPropertyNodeFlags::Expanded, true); } // Add this node to it's parent. Note that no sorting happens here, so the parent's // list of child nodes will not be in the correct order. We'll keep track of which // nodes we added children to so we can sort them after we're finished adding new nodes. ParentLevelNode->AddChildNode(NewCategoryNode); ParentNodesToSort.AddUnique( ParentLevelNode.Get() ); } // Descend into the newly created category by using this node as the new parent ParentLevelNode = NewCategoryNode; } } } } else { // Iterate over all fields, creating items. for( TFieldIterator<UProperty> It(BaseClass.Get()); It; ++It ) { const bool bShowIfNonHiddenEditableProperty = (*It)->HasAnyPropertyFlags(CPF_Edit) && !FEditorCategoryUtils::IsCategoryHiddenFromClass(BaseClass.Get(), FObjectEditorUtils::GetCategory(*It)); const bool bShowIfDisableEditOnInstance = !(*It)->HasAnyPropertyFlags(CPF_DisableEditOnInstance) || bShouldShowDisableEditOnInstance; if (bShouldShowHiddenProperties || (bShowIfNonHiddenEditableProperty && bShowIfDisableEditOnInstance)) { UProperty* CurProp = *It; if( SinglePropertyName == NAME_None || CurProp->GetFName() == SinglePropertyName ) { TSharedPtr<FItemPropertyNode> NewItemNode( new FItemPropertyNode ); FPropertyNodeInitParams InitParams; InitParams.ParentNode = SharedThis(this); InitParams.Property = CurProp; InitParams.ArrayOffset = 0; InitParams.ArrayIndex = INDEX_NONE; InitParams.bAllowChildren = SinglePropertyName == NAME_None; InitParams.bForceHiddenPropertyVisibility = bShouldShowHiddenProperties; InitParams.bCreateDisableEditOnInstanceNodes = bShouldShowDisableEditOnInstance; NewItemNode->InitNode( InitParams ); AddChildNode(NewItemNode); if( SinglePropertyName != NAME_None ) { // Generate no other children break; } } } } } }