// Copyright Epic Games, Inc. All Rights Reserved. #include "SMaterialParametersOverviewWidget.h" #include "MaterialEditor/DEditorFontParameterValue.h" #include "MaterialEditor/DEditorMaterialLayersParameterValue.h" #include "MaterialEditor/DEditorScalarParameterValue.h" #include "MaterialEditor/DEditorStaticComponentMaskParameterValue.h" #include "MaterialEditor/DEditorStaticSwitchParameterValue.h" #include "MaterialEditor/DEditorTextureParameterValue.h" #include "MaterialEditor/DEditorVectorParameterValue.h" #include "MaterialEditor/MaterialEditorInstanceConstant.h" #include "Materials/Material.h" #include "PropertyHandle.h" #include "Modules/ModuleManager.h" #include "PropertyEditorModule.h" #include "ISinglePropertyView.h" #include "Materials/MaterialInstanceConstant.h" #include "Styling/AppStyle.h" #include "PropertyCustomizationHelpers.h" #include "ScopedTransaction.h" #include "IPropertyRowGenerator.h" #include "Widgets/Views/STreeView.h" #include "IDetailTreeNode.h" #include "AssetThumbnail.h" #include "MaterialEditorInstanceDetailCustomization.h" #include "MaterialPropertyHelpers.h" #include "DetailWidgetRow.h" #include "Widgets/Input/SCheckBox.h" #include "EditorSupportDelegates.h" #include "Widgets/Images/SImage.h" #include "MaterialEditor/MaterialEditorPreviewParameters.h" #include "Widgets/Input/SButton.h" #include "Widgets/Text/SInlineEditableTextBlock.h" #include "Materials/MaterialFunction.h" #include "Materials/MaterialFunctionInstance.h" #include "Materials/MaterialFunctionInterface.h" #include "Materials/MaterialExpressionTextureSampleParameter.h" #include "Framework/Application/SlateApplication.h" #include "Widgets/Input/SEditableTextBox.h" #include "Curves/CurveLinearColor.h" #include "Curves/CurveLinearColorAtlas.h" #include "Widgets/Views/SExpanderArrow.h" #include "Widgets/Layout/SWidgetSwitcher.h" #include "MaterialEditor/DEditorRuntimeVirtualTextureParameterValue.h" #include "MaterialEditor/DEditorSparseVolumeTextureParameterValue.h" #include "ThumbnailRendering/ThumbnailManager.h" #include "Styling/StyleColors.h" #define LOCTEXT_NAMESPACE "MaterialLayerCustomization" FString SMaterialParametersOverviewTreeItem::GetCurvePath(UDEditorScalarParameterValue* Parameter) const { FString Path = Parameter->AtlasData.Curve->GetPathName(); return Path; } const FSlateBrush* SMaterialParametersOverviewTreeItem::GetBorderImage() const { return FAppStyle::Get().GetBrush("DetailsView.CategoryMiddle"); } FSlateColor SMaterialParametersOverviewTreeItem::GetOuterBackgroundColor(TSharedPtr InParamData) const { if (IsHovered() || InParamData->StackDataType == EStackDataType::Group) { return FAppStyle::Get().GetSlateColor("Colors.Header"); } return FAppStyle::Get().GetSlateColor("Colors.Panel"); } void SMaterialParametersOverviewTreeItem::RefreshOnRowChange(const FAssetData& AssetData, TSharedPtr InTree) { if (InTree.IsValid()) { InTree->CreateGroupsWidget(); } } void SMaterialParametersOverviewTreeItem::Construct(const FArguments& InArgs, const TSharedRef& InOwnerTableView) { StackParameterData = InArgs._StackParameterData; MaterialEditorInstance = InArgs._MaterialEditorInstance; Tree = InArgs._InTree; TSharedRef LeftSideWidget = SNullWidget::NullWidget; TSharedRef RightSideWidget = SNullWidget::NullWidget; FText NameOverride; TSharedRef WrapperWidget = SNew(SVerticalBox); // GROUP -------------------------------------------------- if (StackParameterData->StackDataType == EStackDataType::Group) { NameOverride = FText::FromName(StackParameterData->Group.GroupName); LeftSideWidget = SNew(STextBlock) .TransformPolicy(ETextTransformPolicy::ToUpper) .Text(NameOverride) .Font(FAppStyle::Get().GetFontStyle("PropertyWindow.BoldFont")) .TextStyle(FAppStyle::Get(), "DetailsView.CategoryTextStyle"); } // END GROUP // PROPERTY ---------------------------------------------- bool bisPaddedProperty = false; if (StackParameterData->StackDataType == EStackDataType::Property) { UDEditorStaticComponentMaskParameterValue* CompMaskParam = Cast(StackParameterData->Parameter); UDEditorVectorParameterValue* VectorParam = Cast(StackParameterData->Parameter); UDEditorScalarParameterValue* ScalarParam = Cast(StackParameterData->Parameter); UDEditorTextureParameterValue* TextureParam = Cast(StackParameterData->Parameter); TAttribute IsParamEnabled = TAttribute::Create(TAttribute::FGetter::CreateStatic(&FMaterialPropertyHelpers::IsOverriddenExpression, StackParameterData->Parameter)); NameOverride = FText::FromName(StackParameterData->Parameter->ParameterInfo.Name); IDetailTreeNode& Node = *StackParameterData->ParameterNode; TSharedPtr GeneratedRow = StaticCastSharedPtr(Node.GetRow()); IDetailPropertyRow& Row = *GeneratedRow.Get(); Row.DisplayName(NameOverride); if (VectorParam && VectorParam->bIsUsedAsChannelMask) { FOnGetPropertyComboBoxStrings GetMaskStrings = FOnGetPropertyComboBoxStrings::CreateStatic(&FMaterialPropertyHelpers::GetVectorChannelMaskComboBoxStrings); FOnGetPropertyComboBoxValue GetMaskValue = FOnGetPropertyComboBoxValue::CreateStatic(&FMaterialPropertyHelpers::GetVectorChannelMaskValue, StackParameterData->Parameter); FOnPropertyComboBoxValueSelected SetMaskValue = FOnPropertyComboBoxValueSelected::CreateStatic(&FMaterialPropertyHelpers::SetVectorChannelMaskValue, StackParameterData->ParameterNode->CreatePropertyHandle(), StackParameterData->Parameter, (UObject*)MaterialEditorInstance); FDetailWidgetRow& CustomWidget = Row.CustomWidget(); CustomWidget .FilterString(NameOverride) .NameContent() [ SNew(STextBlock) .Text(NameOverride) .ToolTipText(FMaterialPropertyHelpers::GetParameterExpressionDescription(StackParameterData->Parameter, MaterialEditorInstance)) .Font(FAppStyle::GetFontStyle(TEXT("PropertyWindow.NormalFont"))) ] .ValueContent() .MaxDesiredWidth(200.0f) [ SNew(SHorizontalBox) + SHorizontalBox::Slot() .FillWidth(1.0f) [ SNew(SHorizontalBox) + SHorizontalBox::Slot() .HAlign(HAlign_Left) .AutoWidth() [ PropertyCustomizationHelpers::MakePropertyComboBox(StackParameterData->ParameterNode->CreatePropertyHandle(), GetMaskStrings, GetMaskValue, SetMaskValue) ] ] ]; } else if (ScalarParam && ScalarParam->AtlasData.bIsUsedAsAtlasPosition) { const FText ParameterName = FText::FromName(StackParameterData->Parameter->ParameterInfo.Name); FDetailWidgetRow& CustomWidget = Row.CustomWidget(); CustomWidget .FilterString(ParameterName) .NameContent() [ SNew(STextBlock) .Text(ParameterName) .ToolTipText(FMaterialPropertyHelpers::GetParameterExpressionDescription(StackParameterData->Parameter, MaterialEditorInstance)) .Font(FAppStyle::GetFontStyle(TEXT("PropertyWindow.NormalFont"))) ] .ValueContent() .HAlign(HAlign_Fill) .MaxDesiredWidth(400.0f) [ SNew(SObjectPropertyEntryBox) .ObjectPath(this, &SMaterialParametersOverviewTreeItem::GetCurvePath, ScalarParam) .AllowedClass(UCurveLinearColor::StaticClass()) .NewAssetFactories(TArray()) .DisplayThumbnail(true) .ThumbnailPool(Tree.Pin()->GetTreeThumbnailPool()) .OnShouldFilterAsset(FOnShouldFilterAsset::CreateStatic(&FMaterialPropertyHelpers::OnShouldFilterCurveAsset, ScalarParam->AtlasData.Atlas)) .OnShouldSetAsset(FOnShouldSetAsset::CreateStatic(&FMaterialPropertyHelpers::OnShouldSetCurveAsset, ScalarParam->AtlasData.Atlas)) .OnObjectChanged(FOnSetObject::CreateStatic(&FMaterialPropertyHelpers::SetPositionFromCurveAsset, ScalarParam->AtlasData.Atlas, ScalarParam, StackParameterData->ParameterHandle, (UObject*)MaterialEditorInstance)) .DisplayCompactSize(true) ]; } else if (TextureParam) { UMaterial *Material = MaterialEditorInstance->PreviewMaterial; if (Material != nullptr) { UMaterialExpressionTextureSampleParameter* Expression = Material->FindExpressionByGUID(TextureParam->ExpressionId); if (Expression != nullptr) { TWeakObjectPtr SamplerExpression = Expression; TSharedPtr NameWidget; TSharedPtr ValueWidget; FDetailWidgetRow DefaultRow; Row.GetDefaultWidgets(NameWidget, ValueWidget, DefaultRow); FDetailWidgetRow &DetailWidgetRow = Row.CustomWidget(); TSharedPtr NameVerticalBox; DetailWidgetRow.NameContent() [ SAssignNew(NameVerticalBox, SVerticalBox) + SVerticalBox::Slot() .AutoHeight() [ SNew(STextBlock) .Text(FText::FromName(StackParameterData->Parameter->ParameterInfo.Name)) .Font(FAppStyle::GetFontStyle(TEXT("PropertyWindow.NormalFont"))) ] ]; DetailWidgetRow.ValueContent() .MinDesiredWidth(DefaultRow.ValueWidget.MinWidth) .MaxDesiredWidth(DefaultRow.ValueWidget.MaxWidth) [ SNew(SObjectPropertyEntryBox) .PropertyHandle(StackParameterData->ParameterNode->CreatePropertyHandle()) .AllowedClass(UTexture::StaticClass()) .ThumbnailPool(Tree.Pin()->GetTreeThumbnailPool()) .OnShouldFilterAsset_Lambda([SamplerExpression](const FAssetData& AssetData) { if (SamplerExpression.Get()) { bool VirtualTextured = false; AssetData.GetTagValue("VirtualTextureStreaming", VirtualTextured); bool ExpressionIsVirtualTextured = IsVirtualSamplerType(SamplerExpression->SamplerType); return VirtualTextured != ExpressionIsVirtualTextured; } else { return false; } }) ]; static const FName Red("R"); static const FName Green("G"); static const FName Blue("B"); static const FName Alpha("A"); if (!TextureParam->ChannelNames.R.IsEmpty()) { NameVerticalBox->AddSlot() [ SNew(SHorizontalBox) + SHorizontalBox::Slot() .AutoWidth() .Padding(20.0, 2.0, 4.0, 2.0) [ SNew(STextBlock) .Text(FText::FromName(Red)) .Font(FAppStyle::GetFontStyle(TEXT("PropertyWindow.BoldFont"))) ] + SHorizontalBox::Slot() .HAlign(HAlign_Left) .Padding(4.0, 2.0) [ SNew(STextBlock) .Text(TextureParam->ChannelNames.R) .Font(FAppStyle::GetFontStyle(TEXT("PropertyWindow.NormalFont"))) ] ]; } if (!TextureParam->ChannelNames.G.IsEmpty()) { NameVerticalBox->AddSlot() [ SNew(SHorizontalBox) + SHorizontalBox::Slot() .Padding(20.0, 2.0, 4.0, 2.0) .AutoWidth() [ SNew(STextBlock) .Text(FText::FromName(Green)) .Font(FAppStyle::GetFontStyle(TEXT("PropertyWindow.BoldFont"))) ] + SHorizontalBox::Slot() .HAlign(HAlign_Left) .Padding(4.0, 2.0) [ SNew(STextBlock) .Text(TextureParam->ChannelNames.G) .Font(FAppStyle::GetFontStyle(TEXT("PropertyWindow.NormalFont"))) ] ]; } if (!TextureParam->ChannelNames.B.IsEmpty()) { NameVerticalBox->AddSlot() [ SNew(SHorizontalBox) + SHorizontalBox::Slot() .Padding(20.0, 2.0, 4.0, 2.0) .AutoWidth() [ SNew(STextBlock) .Text(FText::FromName(Blue)) .Font(FAppStyle::GetFontStyle(TEXT("PropertyWindow.BoldFont"))) ] + SHorizontalBox::Slot() .HAlign(HAlign_Left) .Padding(4.0, 2.0) [ SNew(STextBlock) .Text(TextureParam->ChannelNames.B) .Font(FAppStyle::GetFontStyle(TEXT("PropertyWindow.NormalFont"))) ] ]; } if (!TextureParam->ChannelNames.A.IsEmpty()) { NameVerticalBox->AddSlot() [ SNew(SHorizontalBox) + SHorizontalBox::Slot() .Padding(20.0, 2.0, 4.0, 2.0) .AutoWidth() [ SNew(STextBlock) .Text(FText::FromName(Alpha)) .Font(FAppStyle::GetFontStyle(TEXT("PropertyWindow.BoldFont"))) ] + SHorizontalBox::Slot() .HAlign(HAlign_Left) .Padding(4.0, 2.0) [ SNew(STextBlock) .Text(TextureParam->ChannelNames.A) .Font(FAppStyle::GetFontStyle(TEXT("PropertyWindow.NormalFont"))) ] ]; } } } } else if (CompMaskParam) { TSharedPtr RMaskProperty = StackParameterData->ParameterNode->CreatePropertyHandle()->GetChildHandle("R"); TSharedPtr GMaskProperty = StackParameterData->ParameterNode->CreatePropertyHandle()->GetChildHandle("G"); TSharedPtr BMaskProperty = StackParameterData->ParameterNode->CreatePropertyHandle()->GetChildHandle("B"); TSharedPtr AMaskProperty = StackParameterData->ParameterNode->CreatePropertyHandle()->GetChildHandle("A"); FDetailWidgetRow& CustomWidget = Row.CustomWidget(); CustomWidget .FilterString(NameOverride) .NameContent() [ SNew(SHorizontalBox) + SHorizontalBox::Slot() .VAlign(VAlign_Center) [ SNew(STextBlock) .Text(NameOverride) .ToolTipText(FMaterialPropertyHelpers::GetParameterExpressionDescription(StackParameterData->Parameter, MaterialEditorInstance)) .Font(FAppStyle::GetFontStyle(TEXT("PropertyWindow.NormalFont"))) ] ] .ValueContent() .MaxDesiredWidth(200.0f) [ SNew(SHorizontalBox) + SHorizontalBox::Slot() .FillWidth(1.0f) [ SNew(SHorizontalBox) + SHorizontalBox::Slot() .HAlign(HAlign_Left) .AutoWidth() [ RMaskProperty->CreatePropertyNameWidget() ] + SHorizontalBox::Slot() .HAlign(HAlign_Left) .AutoWidth() [ RMaskProperty->CreatePropertyValueWidget() ] + SHorizontalBox::Slot() .HAlign(HAlign_Left) .Padding(FMargin(10.0f, 0.0f, 0.0f, 0.0f)) .AutoWidth() [ GMaskProperty->CreatePropertyNameWidget() ] + SHorizontalBox::Slot() .HAlign(HAlign_Left) .AutoWidth() [ GMaskProperty->CreatePropertyValueWidget() ] + SHorizontalBox::Slot() .HAlign(HAlign_Left) .Padding(FMargin(10.0f, 0.0f, 0.0f, 0.0f)) .AutoWidth() [ BMaskProperty->CreatePropertyNameWidget() ] + SHorizontalBox::Slot() .HAlign(HAlign_Left) .AutoWidth() [ BMaskProperty->CreatePropertyValueWidget() ] + SHorizontalBox::Slot() .HAlign(HAlign_Left) .Padding(FMargin(10.0f, 0.0f, 0.0f, 0.0f)) .AutoWidth() [ AMaskProperty->CreatePropertyNameWidget() ] + SHorizontalBox::Slot() .HAlign(HAlign_Left) .AutoWidth() [ AMaskProperty->CreatePropertyValueWidget() ] ] ]; } else { if (TSharedPtr PropertyHandle = StackParameterData->ParameterNode->CreatePropertyHandle()) { PropertyHandle->MarkResetToDefaultCustomized(true); } FDetailWidgetDecl* CustomNameWidget = Row.CustomNameWidget(); if (CustomNameWidget) { (*CustomNameWidget) [ SNew(SHorizontalBox) +SHorizontalBox::Slot() .VAlign(VAlign_Center) [ SNew(STextBlock) .Text(NameOverride) .ToolTipText(FMaterialPropertyHelpers::GetParameterExpressionDescription(StackParameterData->Parameter, MaterialEditorInstance)) .Font(FAppStyle::GetFontStyle(TEXT("PropertyWindow.NormalFont"))) ] ]; } else { Row.ToolTip(FMaterialPropertyHelpers::GetParameterExpressionDescription(StackParameterData->Parameter, MaterialEditorInstance)); } bisPaddedProperty = true; } FNodeWidgets NodeWidgets = Node.CreateNodeWidgets(); LeftSideWidget = NodeWidgets.NameWidget.ToSharedRef(); RightSideWidget = NodeWidgets.ValueWidget.ToSharedRef(); } // END PROPERTY // PROPERTY CHILD ---------------------------------------- if (StackParameterData->StackDataType == EStackDataType::PropertyChild) { FNodeWidgets NodeWidgets = StackParameterData->ParameterNode->CreateNodeWidgets(); LeftSideWidget = NodeWidgets.NameWidget.ToSharedRef(); RightSideWidget = NodeWidgets.ValueWidget.ToSharedRef(); } // END PROPERTY CHILD // FINAL WRAPPER { FDetailColumnSizeData& ColumnSizeData = InArgs._InTree->GetColumnSizeData(); float ValuePadding = bisPaddedProperty ? 20.0f : 0.0f; WrapperWidget->AddSlot() .AutoHeight() [ SNew(SBorder) .BorderImage(FAppStyle::Get().GetBrush("DetailsView.GridLine")) .Padding(FMargin(0, 0, 0, 1)) [ SNew(SBorder) .Padding(3.0f) .BorderImage(this, &SMaterialParametersOverviewTreeItem::GetBorderImage) .BorderBackgroundColor(this, &SMaterialParametersOverviewTreeItem::GetOuterBackgroundColor, StackParameterData) [ SNew(SSplitter) .Style(FAppStyle::Get(), "DetailsView.Splitter") .PhysicalSplitterHandleSize(1.0f) .HitDetectionSplitterHandleSize(5.0f) + SSplitter::Slot() .Value(ColumnSizeData.GetNameColumnWidth()) .OnSlotResized(ColumnSizeData.GetOnNameColumnResized()) .Value(0.25f) [ SNew(SHorizontalBox) + SHorizontalBox::Slot() .AutoWidth() .VAlign(VAlign_Center) .Padding(FMargin(3.0f)) [ SNew(SExpanderArrow, SharedThis(this)) ] + SHorizontalBox::Slot() .Padding(FMargin(2.0f)) .VAlign(VAlign_Center) [ LeftSideWidget ] ] + SSplitter::Slot() .Value(ColumnSizeData.GetValueColumnWidth()) .OnSlotResized(ColumnSizeData.GetOnValueColumnResized()) [ SNew(SHorizontalBox) + SHorizontalBox::Slot() .Padding(FMargin(5.0f, 2.0f, 5.0, 2.0f)) .HAlign(HAlign_Left) .VAlign(VAlign_Center) [ RightSideWidget ] ] ] ] ]; } this->ChildSlot [ WrapperWidget ]; STableRow< TSharedPtr >::ConstructInternal( STableRow::FArguments() .Style(FAppStyle::Get(), "DetailsView.TreeView.TableRow") .ShowSelection(false), InOwnerTableView ); } void SMaterialParametersOverviewTree::Construct(const FArguments& InArgs) { bHasAnyParameters = false; MaterialEditorInstance = InArgs._InMaterialEditorInstance; Owner = InArgs._InOwner; SelectMaterialNodeDelegate = InArgs._SelectMaterialNode; CreateGroupsWidget(); STreeView>::Construct( STreeView::FArguments() .TreeItemsSource(&SortedParameters) .SelectionMode(ESelectionMode::None) .OnGenerateRow(this, &SMaterialParametersOverviewTree::OnGenerateRowMaterialLayersFunctionsTreeView) .OnGetChildren(this, &SMaterialParametersOverviewTree::OnGetChildrenMaterialLayersFunctionsTreeView) .OnExpansionChanged(this, &SMaterialParametersOverviewTree::OnExpansionChanged) .ExternalScrollbar(InArgs._InScrollbar) ); } TSharedRef< ITableRow > SMaterialParametersOverviewTree::OnGenerateRowMaterialLayersFunctionsTreeView(TSharedPtr Item, const TSharedRef< STableViewBase >& OwnerTable) { TSharedRef< SMaterialParametersOverviewTreeItem > ReturnRow = SNew(SMaterialParametersOverviewTreeItem, OwnerTable) .StackParameterData(Item) .MaterialEditorInstance(MaterialEditorInstance) .InTree(SharedThis(this)); return ReturnRow; } void SMaterialParametersOverviewTree::OnGetChildrenMaterialLayersFunctionsTreeView(TSharedPtr InParent, TArray< TSharedPtr >& OutChildren) { OutChildren = InParent->Children; } void SMaterialParametersOverviewTree::OnExpansionChanged(TSharedPtr Item, bool bIsExpanded) { bool* ExpansionValue = MaterialEditorInstance->OriginalMaterial->ParameterOverviewExpansion.Find(Item->NodeKey); if (ExpansionValue == nullptr) { MaterialEditorInstance->OriginalMaterial->ParameterOverviewExpansion.Add(Item->NodeKey, bIsExpanded); } else if (*ExpansionValue != bIsExpanded) { MaterialEditorInstance->OriginalMaterial->ParameterOverviewExpansion.Emplace(Item->NodeKey, bIsExpanded); } // Expand any children that are also expanded for (auto Child : Item->Children) { bool* ChildExpansionValue = MaterialEditorInstance->OriginalMaterial->ParameterOverviewExpansion.Find(Child->NodeKey); if (ChildExpansionValue != nullptr && *ChildExpansionValue == true) { SetItemExpansion(Child, true); } } } void SMaterialParametersOverviewTree::SetParentsExpansionState() { for (const auto& Pair : SortedParameters) { if (Pair->Children.Num()) { bool* bIsExpanded = MaterialEditorInstance->OriginalMaterial->ParameterOverviewExpansion.Find(Pair->NodeKey); if (bIsExpanded) { SetItemExpansion(Pair, *bIsExpanded); } else { SetItemExpansion(Pair, true); } } } } TSharedPtr SMaterialParametersOverviewTree::GetTreeThumbnailPool() { return UThumbnailManager::Get().GetSharedThumbnailPool(); } void SMaterialParametersOverviewTree::CreateGroupsWidget() { check(MaterialEditorInstance); UnsortedParameters.Reset(); SortedParameters.Reset(); const TArray> TestData = GetOwner().Pin()->GetGenerator()->GetRootTreeNodes(); if (TestData.Num() == 0) { return; } TSharedPtr Category = TestData[0]; TSharedPtr ParameterGroups; TArray> Children; Category->GetChildren(Children); for (int32 ChildIdx = 0; ChildIdx < Children.Num(); ChildIdx++) { TSharedPtr PropertyHandle = Children[ChildIdx]->CreatePropertyHandle(); if (PropertyHandle.IsValid() && PropertyHandle->GetProperty() && PropertyHandle->GetProperty()->GetName() == "ParameterGroups") { ParameterGroups = Children[ChildIdx]; break; } } Children.Empty(); // the order should correspond to UnsortedParameters exactly TArray> DeferredSearches; if (ParameterGroups.IsValid()) { ParameterGroups->GetChildren(Children); for (int32 GroupIdx = 0; GroupIdx < Children.Num(); ++GroupIdx) { TArray GroupPtrs; TSharedPtr ChildHandle = Children[GroupIdx]->CreatePropertyHandle(); ChildHandle->AccessRawData(GroupPtrs); auto GroupIt = GroupPtrs.CreateConstIterator(); const FEditorParameterGroup* ParameterGroupPtr = reinterpret_cast(*GroupIt); if (!ParameterGroupPtr) { continue; } const FEditorParameterGroup& ParameterGroup = *ParameterGroupPtr; if (ParameterGroup.GroupName == FMaterialPropertyHelpers::LayerParamName) { // Don't create or show the material layer parameter info in this UI continue; } for (int32 ParamIdx = 0; ParamIdx < ParameterGroup.Parameters.Num(); ParamIdx++) { UDEditorParameterValue* Parameter = ParameterGroup.Parameters[ParamIdx]; if (Parameter->ParameterInfo.Association == EMaterialParameterAssociation::GlobalParameter) { bHasAnyParameters = true; TSharedPtr ParametersArrayProperty = ChildHandle->GetChildHandle("Parameters"); TSharedPtr ParameterProperty = ParametersArrayProperty->GetChildHandle(ParamIdx); TSharedPtr ParameterValueProperty = ParameterProperty->GetChildHandle("ParameterValue"); FUnsortedParamData NonLayerProperty; UDEditorScalarParameterValue* ScalarParam = Cast(Parameter); UDEditorVectorParameterValue* VectorParam = Cast(Parameter); if (ScalarParam && ScalarParam->SliderMax > ScalarParam->SliderMin) { ParameterValueProperty->SetInstanceMetaData("UIMin", FString::Printf(TEXT("%f"), ScalarParam->SliderMin)); ParameterValueProperty->SetInstanceMetaData("UIMax", FString::Printf(TEXT("%f"), ScalarParam->SliderMax)); } if (VectorParam) { static const FName Red("R"); static const FName Green("G"); static const FName Blue("B"); static const FName Alpha("A"); if (!VectorParam->ChannelNames.R.IsEmpty()) { ParameterProperty->GetChildHandle(Red)->SetPropertyDisplayName(VectorParam->ChannelNames.R); } if (!VectorParam->ChannelNames.G.IsEmpty()) { ParameterProperty->GetChildHandle(Green)->SetPropertyDisplayName(VectorParam->ChannelNames.G); } if (!VectorParam->ChannelNames.B.IsEmpty()) { ParameterProperty->GetChildHandle(Blue)->SetPropertyDisplayName(VectorParam->ChannelNames.B); } if (!VectorParam->ChannelNames.A.IsEmpty()) { ParameterProperty->GetChildHandle(Alpha)->SetPropertyDisplayName(VectorParam->ChannelNames.A); } } NonLayerProperty.Parameter = Parameter; NonLayerProperty.ParameterGroup = ParameterGroup; NonLayerProperty.UnsortedName = Parameter->ParameterInfo.Name; DeferredSearches.Add(ParameterValueProperty); UnsortedParameters.Add(NonLayerProperty); } } } } checkf(UnsortedParameters.Num() == DeferredSearches.Num(), TEXT("Internal inconsistency: number of node searches does not match the number of properties")); TArray> DeferredResults = GetOwner().Pin()->GetGenerator()->FindTreeNodes(DeferredSearches); checkf(UnsortedParameters.Num() == DeferredResults.Num(), TEXT("Internal inconsistency: number of node search results does not match the number of properties")); for (int Idx = 0, NumUnsorted = UnsortedParameters.Num(); Idx < NumUnsorted; ++Idx) { FUnsortedParamData& NonLayerProperty = UnsortedParameters[Idx]; NonLayerProperty.ParameterNode = DeferredResults[Idx]; NonLayerProperty.ParameterHandle = NonLayerProperty.ParameterNode->CreatePropertyHandle(); } ShowSubParameters(); RequestTreeRefresh(); SetParentsExpansionState(); } bool SMaterialParametersOverviewTree::Private_OnItemDoubleClicked(TSharedPtr TheItem) { if (STreeView>::Private_OnItemDoubleClicked(TheItem)) { return true; } if (!SelectMaterialNodeDelegate.IsBound() || !TheItem.IsValid() || !TheItem->Parameter || !TheItem->Parameter->ExpressionId.IsValid()) { return false; } SelectMaterialNodeDelegate.Execute(TheItem->Parameter->ExpressionId); return true; } void SMaterialParametersOverviewTree::ShowSubParameters() { for (FUnsortedParamData Property : UnsortedParameters) { UDEditorParameterValue* Parameter = Property.Parameter; { TSharedPtr GroupProperty(new FSortedParamData()); GroupProperty->StackDataType = EStackDataType::Group; GroupProperty->ParameterInfo.Index = Parameter->ParameterInfo.Index; GroupProperty->ParameterInfo.Association = Parameter->ParameterInfo.Association; GroupProperty->Group = Property.ParameterGroup; GroupProperty->NodeKey = FString::FromInt(GroupProperty->ParameterInfo.Index) + FString::FromInt(GroupProperty->ParameterInfo.Association) + Property.ParameterGroup.GroupName.ToString(); bool bAddNewGroup = true; for (TSharedPtr GroupChild : SortedParameters) { if (GroupChild->NodeKey == GroupProperty->NodeKey) { bAddNewGroup = false; } } if (bAddNewGroup) { SortedParameters.Add(GroupProperty); } TSharedPtr ChildProperty(new FSortedParamData()); ChildProperty->StackDataType = EStackDataType::Property; ChildProperty->Parameter = Parameter; ChildProperty->ParameterInfo.Index = Parameter->ParameterInfo.Index; ChildProperty->ParameterInfo.Association = Parameter->ParameterInfo.Association; ChildProperty->ParameterNode = Property.ParameterNode; ChildProperty->PropertyName = Property.UnsortedName; ChildProperty->NodeKey = FString::FromInt(ChildProperty->ParameterInfo.Index) + FString::FromInt(ChildProperty->ParameterInfo.Association) + Property.ParameterGroup.GroupName.ToString() + Property.UnsortedName.ToString(); UDEditorStaticComponentMaskParameterValue* CompMaskParam = Cast(Parameter); // No children for masks if (!CompMaskParam) { TArray> ParamChildren; Property.ParameterNode->GetChildren(ParamChildren); for (int32 ParamChildIdx = 0; ParamChildIdx < ParamChildren.Num(); ParamChildIdx++) { TSharedPtr ParamChildProperty(new FSortedParamData()); ParamChildProperty->StackDataType = EStackDataType::PropertyChild; ParamChildProperty->ParameterNode = ParamChildren[ParamChildIdx]; ParamChildProperty->ParameterHandle = ParamChildProperty->ParameterNode->CreatePropertyHandle(); ParamChildProperty->ParameterInfo.Index = Parameter->ParameterInfo.Index; ParamChildProperty->ParameterInfo.Association = Parameter->ParameterInfo.Association; ParamChildProperty->Parameter = ChildProperty->Parameter; ChildProperty->Children.Add(ParamChildProperty); } } UDEditorRuntimeVirtualTextureParameterValue* VTParameter = Cast(Parameter); UDEditorSparseVolumeTextureParameterValue* SVTParameter = Cast(Parameter); // Don't add child property to this group if parameter is of type 'Virtual Texture' or 'Sparse Volume Texture' if (!VTParameter && !SVTParameter) { for (TSharedPtr GroupChild : SortedParameters) { if (GroupChild->Group.GroupName == Property.ParameterGroup.GroupName && GroupChild->ParameterInfo.Association == ChildProperty->ParameterInfo.Association && GroupChild->ParameterInfo.Index == ChildProperty->ParameterInfo.Index) { GroupChild->Children.Add(ChildProperty); } } } } } } const FSlateBrush* SMaterialParametersOverviewPanel::GetBackgroundImage() const { return FAppStyle::GetBrush("DetailsView.CategoryTop"); } int32 SMaterialParametersOverviewPanel::GetPanelIndex() const { return NestedTree && NestedTree->HasAnyParameters() ? 1 : 0; } void SMaterialParametersOverviewPanel::Refresh() { TSharedPtr HeaderBox; NestedTree->CreateGroupsWidget(); FOnClicked OnChildButtonClicked = FOnClicked(); if (MaterialEditorInstance->OriginalFunction) { OnChildButtonClicked = FOnClicked::CreateStatic(&FMaterialPropertyHelpers::OnClickedSaveNewFunctionInstance, ImplicitConv(MaterialEditorInstance->OriginalFunction), ImplicitConv(MaterialEditorInstance->PreviewMaterial), ImplicitConv(MaterialEditorInstance)); } else { OnChildButtonClicked = FOnClicked::CreateStatic(&FMaterialPropertyHelpers::OnClickedSaveNewMaterialInstance, ImplicitConv(MaterialEditorInstance->OriginalMaterial), ImplicitConv(MaterialEditorInstance)); } if (NestedTree->HasAnyParameters()) { this->ChildSlot [ SNew(SVerticalBox) + SVerticalBox::Slot() .Padding(0.0f) [ SNew(SVerticalBox) + SVerticalBox::Slot() .AutoHeight() [ SAssignNew(HeaderBox, SHorizontalBox) ] + SVerticalBox::Slot() .Padding(0.0f) [ SNew(SHorizontalBox) + SHorizontalBox::Slot() .HAlign(HAlign_Fill) [ NestedTree.ToSharedRef() ] + SHorizontalBox::Slot() .HAlign(HAlign_Right) .AutoWidth() [ SNew(SBox) .WidthOverride(16.0f) [ ExternalScrollbar.ToSharedRef() ] ] ] ] ]; HeaderBox->AddSlot() .FillWidth(1.0f) [ SNullWidget::NullWidget ]; if (NestedTree->HasAnyParameters()) { HeaderBox->AddSlot() .AutoWidth() .Padding(2.0f) [ SNew(SButton) .Text(LOCTEXT("SaveChild", "Save Child")) .HAlign(HAlign_Center) .OnClicked(OnChildButtonClicked) .ToolTipText(LOCTEXT("SaveToChildInstance", "Save To Child Instance")) ]; } } else { this->ChildSlot [ SNew(SBox) .Padding(10.0f) .HAlign(HAlign_Center) [ SNew(STextBlock) .Text(LOCTEXT("ConnectMaterialParametersToFillList", "Connect a parameter to see it here.")) ] ]; } } void SMaterialParametersOverviewPanel::Construct(const FArguments& InArgs) { ExternalScrollbar = SNew(SScrollBar); TSharedPtr InGenerator = InArgs._InGenerator; Generator = InGenerator; NestedTree = SNew(SMaterialParametersOverviewTree) .InMaterialEditorInstance(InArgs._InMaterialEditorInstance) .InOwner(SharedThis(this)) .InScrollbar(ExternalScrollbar) .SelectMaterialNode(InArgs._SelectMaterialNode); MaterialEditorInstance = InArgs._InMaterialEditorInstance; Refresh(); } void SMaterialParametersOverviewPanel::UpdateEditorInstance(UMaterialEditorPreviewParameters* InMaterialEditorInstance) { NestedTree->MaterialEditorInstance = InMaterialEditorInstance; Refresh(); } TSharedPtr SMaterialParametersOverviewPanel::GetGenerator() { return Generator.Pin(); } #undef LOCTEXT_NAMESPACE