void SDetailsViewBase::UpdatePropertyMap() { // Reset everything ClassToPropertyMap.Empty(); ClassesWithProperties.Empty(); // We need to be able to create a new detail layout and properly clean up the old one in the process check(!DetailLayout.IsValid() || DetailLayout.IsUnique()); RootTreeNodes.Empty(); DetailLayout = MakeShareable(new FDetailLayoutBuilderImpl(ClassToPropertyMap, PropertyUtilities.ToSharedRef(), SharedThis(this))); auto RootPropertyNode = GetRootNode(); check(RootPropertyNode.IsValid()); // Currently object property nodes do not provide any useful information other than being a container for its children. We do not draw anything for them. // When we encounter object property nodes, add their children instead of adding them to the tree. UpdatePropertyMapRecursive(*RootPropertyNode, *DetailLayout, NAME_None, RootPropertyNode.Get()); CustomUpdatePropertyMap(); // Ask for custom detail layouts, unless disabled. One reason for disabling custom layouts is that the custom layouts // inhibit our ability to find a single property's tree node. This is problematic for the diff and merge tools, that need // to display and highlight each changed property for the user. We could whitelist 'good' customizations here if // we can make them work with the diff/merge tools. if( !bDisableCustomDetailLayouts ) { QueryCustomDetailLayout(*DetailLayout); } DetailLayout->GenerateDetailLayout(); UpdateFilteredDetails(); }
void SDetailsViewBase::OnShowAllAdvancedClicked() { CurrentFilter.bShowAllAdvanced = !CurrentFilter.bShowAllAdvanced; GetMutableDefault<UEditorStyleSettings>()->bShowAllAdvancedDetails = CurrentFilter.bShowAllAdvanced; GConfig->SetBool(TEXT("/Script/EditorStyle.EditorStyleSettings"), TEXT("bShowAllAdvancedDetails"), GetMutableDefault<UEditorStyleSettings>()->bShowAllAdvancedDetails, GEditorPerProjectIni); UpdateFilteredDetails(); }
/** Called at the end of SetObjectArray after we change the objects being observed */ void SDetailsView::PostSetObject() { DestroyColorPicker(); ColorPropertyNode = nullptr; FPropertyNodeInitParams InitParams; InitParams.ParentNode = nullptr; InitParams.Property = nullptr; InitParams.ArrayOffset = 0; InitParams.ArrayIndex = INDEX_NONE; InitParams.bAllowChildren = true; InitParams.bForceHiddenPropertyVisibility = FPropertySettings::Get().ShowHiddenProperties(); switch ( DetailsViewArgs.DefaultsOnlyVisibility ) { case FDetailsViewArgs::EEditDefaultsOnlyNodeVisibility::Hide: InitParams.bCreateDisableEditOnInstanceNodes = false; break; case FDetailsViewArgs::EEditDefaultsOnlyNodeVisibility::Show: InitParams.bCreateDisableEditOnInstanceNodes = true; break; case FDetailsViewArgs::EEditDefaultsOnlyNodeVisibility::Automatic: InitParams.bCreateDisableEditOnInstanceNodes = HasClassDefaultObject(); break; default: check(false); } for( TSharedPtr<FComplexPropertyNode>& ComplexRootNode : RootPropertyNodes ) { FObjectPropertyNode* RootPropertyNode = ComplexRootNode->AsObjectNode(); RootPropertyNode->InitNode( InitParams ); // Restore existing expanded items RestoreExpandedItems(ComplexRootNode.ToSharedRef()); } UpdatePropertyMaps(); for( auto ExternalRootNode : ExternalRootPropertyNodes ) { if( ExternalRootNode.IsValid() ) { RestoreExpandedItems( ExternalRootNode.Pin().ToSharedRef() ); } } UpdateFilteredDetails(); }
/** * Hides or shows properties based on the passed in filter text * * @param InFilterText The filter text */ void SDetailsViewBase::FilterView(const FString& InFilterText) { TArray<FString> CurrentFilterStrings; FString ParseString = InFilterText; // Remove whitespace from the front and back of the string ParseString.Trim(); ParseString.TrimTrailing(); ParseString.ParseIntoArray(CurrentFilterStrings, TEXT(" "), true); bHasActiveFilter = CurrentFilterStrings.Num() > 0; CurrentFilter.FilterStrings = CurrentFilterStrings; UpdateFilteredDetails(); }
/** Ticks the property view. This function performs a data consistency check */ void SDetailsViewBase::Tick( const FGeometry& AllottedGeometry, const double InCurrentTime, const float InDeltaTime ) { for (int32 i = 0; i < CustomizationClassInstancesPendingDelete.Num(); ++i) { ensure(CustomizationClassInstancesPendingDelete[i].IsUnique()); } if (RootNodePendingKill.IsValid()) { RootNodePendingKill->Disconnect(); RootNodePendingKill.Reset(); } // Empty all the customization instances that need to be deleted CustomizationClassInstancesPendingDelete.Empty(); auto RootPropertyNode = GetRootNode(); check(RootPropertyNode.IsValid()); // Purge any objects that are marked pending kill from the object list if (auto ObjectRoot = RootPropertyNode->AsObjectNode()) { ObjectRoot->PurgeKilledObjects(); } if (DeferredActions.Num() > 0) { // Any deferred actions are likely to cause the node tree to be at least partially rebuilt // Save the expansion state of existing nodes so we can expand them later SaveExpandedItems(); // Execute any deferred actions for (int32 ActionIndex = 0; ActionIndex < DeferredActions.Num(); ++ActionIndex) { DeferredActions[ActionIndex].ExecuteIfBound(); } DeferredActions.Empty(); } if( RootPropertyNode == RootNodePendingKill ) { // Reaquire the root property node. It may have been changed by the deferred actions if something like a blueprint editor forcefully resets a details panel during a posteditchange RootPropertyNode = GetRootNode(); RestoreExpandedItems(); } bool bValidateExternalNodes = true; FPropertyNode::DataValidationResult Result = RootPropertyNode->EnsureDataIsValid(); if (Result == FPropertyNode::PropertiesChanged || Result == FPropertyNode::EditInlineNewValueChanged) { RestoreExpandedItems(); UpdatePropertyMap(); } else if (Result == FPropertyNode::ArraySizeChanged) { RestoreExpandedItems(); UpdateFilteredDetails(); } else if (Result == FPropertyNode::ObjectInvalid) { ForceRefresh(); // All objects are being reset, no need to validate external nodes bValidateExternalNodes = false; } if (bValidateExternalNodes) { for (int32 NodeIndex = 0; NodeIndex < ExternalRootPropertyNodes.Num(); ++NodeIndex) { TSharedPtr<FPropertyNode> PropertyNode = ExternalRootPropertyNodes[NodeIndex].Pin(); if (PropertyNode.IsValid()) { Result = PropertyNode->EnsureDataIsValid(); if (Result == FPropertyNode::PropertiesChanged || Result == FPropertyNode::EditInlineNewValueChanged) { RestoreExpandedItems(PropertyNode); UpdatePropertyMap(); // Note this will invalidate all the external root nodes so there is no need to continue ExternalRootPropertyNodes.Empty(); break; } else if (Result == FPropertyNode::ArraySizeChanged) { RestoreExpandedItems(PropertyNode); UpdateFilteredDetails(); } } else { // Remove the current node if it is no longer valid ExternalRootPropertyNodes.RemoveAt(NodeIndex); --NodeIndex; } } } if (DetailLayout.IsValid()) { DetailLayout->Tick(InDeltaTime); } if (!ColorPropertyNode.IsValid() && bHasOpenColorPicker) { // Destroy the color picker window if the color property node has become invalid DestroyColorPicker(); bHasOpenColorPicker = false; } if (FilteredNodesRequestingExpansionState.Num() > 0) { // change expansion state on the nodes that request it for (TMap<TSharedRef<IDetailTreeNode>, bool >::TConstIterator It(FilteredNodesRequestingExpansionState); It; ++It) { DetailTree->SetItemExpansion(It.Key(), It.Value()); } FilteredNodesRequestingExpansionState.Empty(); } }
void SDetailsViewBase::OnShowAllChildrenIfCategoryMatchesClicked() { CurrentFilter.bShowAllChildrenIfCategoryMatches = !CurrentFilter.bShowAllChildrenIfCategoryMatches; UpdateFilteredDetails(); }
void SDetailsViewBase::OnShowOnlyDifferingClicked() { CurrentFilter.bShowOnlyDiffering = !CurrentFilter.bShowOnlyDiffering; UpdateFilteredDetails(); }
void SDetailsViewBase::OnShowAllAdvancedClicked() { CurrentFilter.bShowAllAdvanced = !CurrentFilter.bShowAllAdvanced; UpdateFilteredDetails(); }
void SDetailsViewBase::OnShowOnlyModifiedClicked() { CurrentFilter.bShowOnlyModifiedProperties = !CurrentFilter.bShowOnlyModifiedProperties; UpdateFilteredDetails(); }
void SDetailsViewBase::RerunCurrentFilter() { UpdateFilteredDetails(); }