void FAbcImportSettingsCustomization::CustomizeDetails(IDetailLayoutBuilder& LayoutBuilder)
{
	TSharedRef<IPropertyHandle> ImportType = LayoutBuilder.GetProperty(GET_MEMBER_NAME_CHECKED(UAbcImportSettings, ImportType));
	
	uint8 EnumValue;
	ImportType->GetValue(EnumValue);
	IDetailCategoryBuilder& CompressionBuilder = LayoutBuilder.EditCategory("Compression");
	CompressionBuilder.SetCategoryVisibility(EnumValue == (uint8)EAlembicImportType::Skeletal);

	IDetailCategoryBuilder& StaticMeshBuilder = LayoutBuilder.EditCategory("StaticMesh");
	StaticMeshBuilder.SetCategoryVisibility(EnumValue == (uint8)EAlembicImportType::StaticMesh);

	FSimpleDelegate OnImportTypeChangedDelegate = FSimpleDelegate::CreateSP(this, &FAbcImportSettingsCustomization::OnImportTypeChanged, &LayoutBuilder);
	ImportType->SetOnPropertyValueChanged(OnImportTypeChangedDelegate);

	if (UAbcImportSettings::Get()->bReimport)
	{
		UEnum* ImportTypeEnum = FindObject<UEnum>(ANY_PACKAGE, TEXT("EAlembicImportType"));		
		static FText RestrictReason = FText::FromString("Unable to change type while reimporting");
		TSharedPtr<FPropertyRestriction> EnumRestriction = MakeShareable(new FPropertyRestriction(RestrictReason));

		for (uint8 EnumIndex = 0; EnumIndex < (ImportTypeEnum->GetMaxEnumValue() + 1); ++EnumIndex)
		{
			if (EnumValue != EnumIndex)
			{
				const FString RestrictValue = ImportTypeEnum->GetDisplayNameTextByValue(EnumIndex).ToString();
				EnumRestriction->AddValue(RestrictValue);
			}
		}		
		ImportType->AddRestriction(EnumRestriction.ToSharedRef());
	}	
}
void FFoliageTypePaintingCustomization::CustomizeDetails(IDetailLayoutBuilder& DetailLayoutBuilder)
{
    // Hide categories we are not going to customize
    FFoliageTypeCustomizationHelpers::HideFoliageCategory(DetailLayoutBuilder, "Procedural");
    FFoliageTypeCustomizationHelpers::HideFoliageCategory(DetailLayoutBuilder, "Reapply");

    // Show all the properties with a reapply condition or that depend on another variable to be relevant
    TMap<const FName, IDetailPropertyRow*> PropertyRowsByName;
    ShowFoliagePropertiesForCategory(DetailLayoutBuilder, "Painting", PropertyRowsByName);
    ShowFoliagePropertiesForCategory(DetailLayoutBuilder, "Placement", PropertyRowsByName);
    ShowFoliagePropertiesForCategory(DetailLayoutBuilder, "InstanceSettings", PropertyRowsByName);

    // Density adjustment factor should only be visible when reapplying
    FFoliageTypeCustomizationHelpers::ModifyFoliagePropertyRow(*PropertyRowsByName.Find(GET_MEMBER_NAME_CHECKED(UFoliageType, DensityAdjustmentFactor)),
            TAttribute<EVisibility>::Create(TAttribute<EVisibility>::FGetter::CreateSP(this, &FFoliageTypePaintingCustomization::GetReapplyModeVisibility)),
            TAttribute<bool>());

    // Set the scale visibility attribute for each axis
    Scaling = DetailLayoutBuilder.GetProperty(GET_MEMBER_NAME_CHECKED(UFoliageType, Scaling));
    ReapplyScaling = DetailLayoutBuilder.GetProperty(GET_MEMBER_NAME_CHECKED(UFoliageType, ReapplyScaling));
    FFoliageTypeCustomizationHelpers::ModifyFoliagePropertyRow(*PropertyRowsByName.Find(GET_MEMBER_NAME_CHECKED(UFoliageType, ScaleX)),
            TAttribute<EVisibility>::Create(TAttribute<EVisibility>::FGetter::CreateSP(this, &FFoliageTypePaintingCustomization::GetScaleVisibility, EAxis::X)),
            TAttribute<bool>());

    FFoliageTypeCustomizationHelpers::ModifyFoliagePropertyRow(*PropertyRowsByName.Find(GET_MEMBER_NAME_CHECKED(UFoliageType, ScaleY)),
            TAttribute<EVisibility>::Create(TAttribute<EVisibility>::FGetter::CreateSP(this, &FFoliageTypePaintingCustomization::GetScaleVisibility, EAxis::Y)),
            TAttribute<bool>());

    FFoliageTypeCustomizationHelpers::ModifyFoliagePropertyRow(*PropertyRowsByName.Find(GET_MEMBER_NAME_CHECKED(UFoliageType, ScaleZ)),
            TAttribute<EVisibility>::Create(TAttribute<EVisibility>::FGetter::CreateSP(this, &FFoliageTypePaintingCustomization::GetScaleVisibility, EAxis::Z)),
            TAttribute<bool>());
}
void FAnimMontageSegmentDetails::CustomizeDetails( IDetailLayoutBuilder& DetailBuilder )
{
	IDetailCategoryBuilder& SegmentCategory = DetailBuilder.EditCategory("Animation Segment", LOCTEXT("AnimationSegmentCategoryTitle", "Animation Segment") );

	SegmentCategory.AddProperty("AnimSegment.AnimReference").DisplayName( LOCTEXT("AnimationReferenceLabel", "Animation Reference") );

	SegmentCategory.AddProperty("AnimSegment.AnimStartTime").DisplayName( LOCTEXT("StartTimeLabel", "Start Time") );
	SegmentCategory.AddProperty("AnimSegment.AnimEndTime").DisplayName( LOCTEXT("EndTimeLabel", "End Time") );

	SegmentCategory.AddProperty("AnimSegment.AnimPlayRate").DisplayName( LOCTEXT("PlayRateLabel", "Play Rate") );
	SegmentCategory.AddProperty("AnimSegment.LoopingCount").DisplayName( LOCTEXT("LoopCountLabel", "Loop Count") );

	TSharedPtr<IPropertyHandle> InPropertyHandle = DetailBuilder.GetProperty("AnimSegment.AnimReference");
	UObject *Object = NULL;
	InPropertyHandle->GetValue(Object);

	UAnimSequenceBase *AnimRef = Cast<UAnimSequenceBase>(Object);
	USkeleton *Skeleton = NULL;
	if(AnimRef != NULL)
	{
		Skeleton = AnimRef->GetSkeleton();
	}

	SegmentCategory.AddCustomRow(FText::GetEmpty(), false)
	[
		SNew(SAnimationSegmentViewport)
		.Skeleton(Skeleton)
		.AnimRef(AnimRef)
		.AnimRefPropertyHandle(DetailBuilder.GetProperty("AnimSegment.AnimReference"))
		.StartTimePropertyHandle(DetailBuilder.GetProperty("AnimSegment.AnimStartTime"))
		.EndTimePropertyHandle(DetailBuilder.GetProperty("AnimSegment.AnimEndTime"))
	];	
}
void FDerivedCustomization::CustomizeDetails(IDetailLayoutBuilder& DetailLayout)
{
	// So now we're customizing UDerivedClass object
	// First, try to hide an inherited property
	{
		// 'HideMe' property is defined in UBaseClass
		TSharedPtr<IPropertyHandle> PropertyToHide = DetailLayout.GetProperty(GET_MEMBER_NAME_CHECKED(UDerivedClass, HideMe));

		PropertyToHide->MarkHiddenByCustomization();
	}
	
	
	{
		// Now grab any struct property (or property that has customized property value widget)
		// Note that this is property defined in UDerivedClass!
		TSharedPtr<IPropertyHandle> TestProperty = DetailLayout.GetProperty(GET_MEMBER_NAME_CHECKED(UDerivedClass, Vector2dProperty));

		// Hide this property
		TestProperty->MarkHiddenByCustomization();

		// Get a category so we can add a TestProperty back to the panel
		IDetailCategoryBuilder& DerivedCategory = DetailLayout.EditCategory("Derived");
		DerivedCategory.AddCustomRow(LOCTEXT("DerivedObjectLabel", "Derived"))
			.NameContent()
			[
				TestProperty->CreatePropertyNameWidget()
			]
		.ValueContent()
			[
				// This will return NullWidget - thats the problem
				TestProperty->CreatePropertyValueWidget()
			];
	}
}
void FDestructibleMeshDetails::CustomizeDetails(IDetailLayoutBuilder& DetailBuilder)
{
		//we always hide bodysetup as it's not useful in this editor
		TSharedPtr<IPropertyHandle> BodySetupHandler = DetailBuilder.GetProperty("BodySetup");
		if (BodySetupHandler.IsValid())
		{
			DetailBuilder.HideProperty(BodySetupHandler);
		}
		
		//rest of customization is just moving stuff out of DefaultDestructibleParameters so it's nicer to view
		TSharedPtr<IPropertyHandle> DefaultParams = DetailBuilder.GetProperty("DefaultDestructibleParameters");
		if (DefaultParams.IsValid() == false)
		{
			return;
		}

		AddStructToDetails("Damage", "DefaultDestructibleParameters.DamageParameters", DetailBuilder);
		AddStructToDetails("Damage", "DefaultDestructibleParameters.AdvancedParameters", DetailBuilder, true, true);
		AddStructToDetails("Debris", "DefaultDestructibleParameters.DebrisParameters", DetailBuilder);
		AddStructToDetails("Flags", "DefaultDestructibleParameters.Flags", DetailBuilder);
		AddStructToDetails("HierarchyDepth", "DefaultDestructibleParameters.SpecialHierarchyDepths", DetailBuilder);
		AddStructToDetails("HierarchyDepth", "DefaultDestructibleParameters.DepthParameters", DetailBuilder, false, true);

		

		//hide the default params as we've taken everything out of it
		DetailBuilder.HideProperty(DefaultParams);
}
/** IDetailCustomization interface */
void FSpeedTreeImportDataDetails::CustomizeDetails(IDetailLayoutBuilder& DetailLayout)
{
	CachedDetailBuilder = &DetailLayout;
	TArray<TWeakObjectPtr<UObject>> EditingObjects;
	DetailLayout.GetObjectsBeingCustomized(EditingObjects);
	check(EditingObjects.Num() == 1);
	SpeedTreeImportData = Cast<USpeedTreeImportData>(EditingObjects[0].Get());
	if (SpeedTreeImportData == nullptr)
	{
		return;
	}

	//We have to hide FilePath category
	DetailLayout.HideCategory(FName(TEXT("File Path")));
	
	//Mesh category Must be the first category (Important)
	DetailLayout.EditCategory(FName(TEXT("Mesh")), FText::GetEmpty(), ECategoryPriority::Important);

	//Get the Materials category
	IDetailCategoryBuilder& MaterialsCategoryBuilder = DetailLayout.EditCategory(FName(TEXT("Materials")));
	TArray<TSharedRef<IPropertyHandle>> MaterialCategoryDefaultProperties;
	MaterialsCategoryBuilder.GetDefaultProperties(MaterialCategoryDefaultProperties);
	
	//We have to make the logic for vertex processing
	TSharedRef<IPropertyHandle> MakeMaterialsCheckProp = DetailLayout.GetProperty(GET_MEMBER_NAME_CHECKED(USpeedTreeImportData, MakeMaterialsCheck));
	MakeMaterialsCheckProp->SetOnPropertyValueChanged(FSimpleDelegate::CreateSP(this, &FSpeedTreeImportDataDetails::OnForceRefresh));

	TSharedRef<IPropertyHandle> IncludeVertexProcessingCheckProp = DetailLayout.GetProperty(GET_MEMBER_NAME_CHECKED(USpeedTreeImportData, IncludeVertexProcessingCheck));
	IncludeVertexProcessingCheckProp->SetOnPropertyValueChanged(FSimpleDelegate::CreateSP(this, &FSpeedTreeImportDataDetails::OnForceRefresh));

	//Hide all properties, we will show them in the correct order with the correct grouping
	for (TSharedRef<IPropertyHandle> Handle : MaterialCategoryDefaultProperties)
	{
		DetailLayout.HideProperty(Handle);
	}

	MaterialsCategoryBuilder.AddProperty(MakeMaterialsCheckProp);
	if (SpeedTreeImportData->MakeMaterialsCheck)
	{
		for (TSharedRef<IPropertyHandle> Handle : MaterialCategoryDefaultProperties)
		{
			const FString& MetaData = Handle->GetMetaData(TEXT("EditCondition"));
			if (MetaData.Compare(TEXT("MakeMaterialsCheck")) == 0 && IncludeVertexProcessingCheckProp->GetProperty() != Handle->GetProperty())
			{
				MaterialsCategoryBuilder.AddProperty(Handle);
			}
		}
		IDetailGroup& VertexProcessingGroup = MaterialsCategoryBuilder.AddGroup(FName(TEXT("VertexProcessingGroup")), LOCTEXT("VertexProcessingGroup_DisplayName", "Vertex Processing"), false, true);
		VertexProcessingGroup.AddPropertyRow(IncludeVertexProcessingCheckProp);
		for (TSharedRef<IPropertyHandle> Handle : MaterialCategoryDefaultProperties)
		{
			const FString& MetaData = Handle->GetMetaData(TEXT("EditCondition"));
			if (MetaData.Compare(TEXT("IncludeVertexProcessingCheck")) == 0)
			{
				VertexProcessingGroup.AddPropertyRow(Handle);
			}
		}
	}
}
void FSpriteDetailsCustomization::BuildTextureSection(IDetailCategoryBuilder& SpriteCategory, IDetailLayoutBuilder& DetailLayout)
{
	// Grab information about the material
	TSharedPtr<IPropertyHandle> DefaultMaterialProperty = DetailLayout.GetProperty(GET_MEMBER_NAME_CHECKED(UPaperSprite, DefaultMaterial));

	FText SourceTextureOverrideLabel;
	if (DefaultMaterialProperty.IsValid())
	{
		UObject* DefaultMaterialAsObject;
		if (DefaultMaterialProperty->GetValue(/*out*/ DefaultMaterialAsObject) == FPropertyAccess::Success)
		{
			if (UMaterialInterface* DefaultMaterialInterface = Cast<UMaterialInterface>(DefaultMaterialAsObject))
			{
				if (UMaterial* DefaultMaterial = DefaultMaterialInterface->GetMaterial())
				{
					// Get a list of sprite samplers
					TArray<const UMaterialExpressionSpriteTextureSampler*> SpriteSamplerExpressions;
					DefaultMaterial->GetAllExpressionsOfType(/*inout*/ SpriteSamplerExpressions);

					// Turn that into a set of labels
					for (const UMaterialExpressionSpriteTextureSampler* Sampler : SpriteSamplerExpressions)
					{
						if (!Sampler->SlotDisplayName.IsEmpty())
						{
							if (Sampler->bSampleAdditionalTextures)
							{
								AdditionalTextureLabels.FindOrAdd(Sampler->AdditionalSlotIndex) = Sampler->SlotDisplayName;
							}
							else
							{
								SourceTextureOverrideLabel = Sampler->SlotDisplayName;
							}
						}
					}
				}
			}
		}
	}

	// Create the base texture widget
	TSharedPtr<IPropertyHandle> SourceTextureProperty = DetailLayout.GetProperty(GET_MEMBER_NAME_CHECKED(UPaperSprite, SourceTexture));
	DetailLayout.HideProperty(SourceTextureProperty);
	SpriteCategory.AddCustomRow(SourceTextureProperty->GetPropertyDisplayName())
		.NameContent()
		[
			CreateTextureNameWidget(SourceTextureProperty, SourceTextureOverrideLabel)
		]
		.ValueContent()
		.MaxDesiredWidth(TOptional<float>())
		[
			SourceTextureProperty->CreatePropertyValueWidget()
		];

	// Create the additional textures widget
	TSharedPtr<IPropertyHandle> AdditionalSourceTexturesProperty = DetailLayout.GetProperty(GET_MEMBER_NAME_CHECKED(UPaperSprite, AdditionalSourceTextures));
	TSharedRef<FDetailArrayBuilder> AdditionalSourceTexturesBuilder = MakeShareable(new FDetailArrayBuilder(AdditionalSourceTexturesProperty.ToSharedRef()));
	AdditionalSourceTexturesBuilder->OnGenerateArrayElementWidget(FOnGenerateArrayElementWidget::CreateSP(this, &FSpriteDetailsCustomization::GenerateAdditionalTextureWidget));
	SpriteCategory.AddCustomBuilder(AdditionalSourceTexturesBuilder);
}
void FSpriteDetailsCustomization::BuildRenderingSection(IDetailCategoryBuilder& RenderingCategory, IDetailLayoutBuilder& DetailLayout)
{
	// Add the rendering geometry mode into the parent container (renamed)
	const FString RenderGeometryTypePropertyPath = FString::Printf(TEXT("%s.%s"), GET_MEMBER_NAME_STRING_CHECKED(UPaperSprite, RenderGeometry), GET_MEMBER_NAME_STRING_CHECKED(FSpritePolygonCollection, GeometryType));
	RenderingCategory.AddProperty(DetailLayout.GetProperty(*RenderGeometryTypePropertyPath))
		.DisplayName(LOCTEXT("RenderGeometryType", "Render Geometry Type"));

	// Show the rendering geometry settings
	TSharedRef<IPropertyHandle> RenderGeometry = DetailLayout.GetProperty(GET_MEMBER_NAME_CHECKED(UPaperSprite, RenderGeometry));
	IDetailPropertyRow& RenderGeometryProperty = RenderingCategory.AddProperty(RenderGeometry);

	// Add the render polygons into advanced (renamed)
	const FString RenderGeometryPolygonsPropertyPath = FString::Printf(TEXT("%s.%s"), GET_MEMBER_NAME_STRING_CHECKED(UPaperSprite, RenderGeometry), GET_MEMBER_NAME_STRING_CHECKED(FSpritePolygonCollection, Polygons));
	RenderingCategory.AddProperty(DetailLayout.GetProperty(*RenderGeometryPolygonsPropertyPath), EPropertyLocation::Advanced)
		.DisplayName(LOCTEXT("RenderPolygons", "Render Polygons"));
}
void FFormatTextDetails::CustomizeDetails( IDetailLayoutBuilder& DetailLayout )
{
	const TArray<TWeakObjectPtr<UObject>> Objects = DetailLayout.GetDetailsView().GetSelectedObjects();
	check(Objects.Num() > 0);

	if (Objects.Num() == 1)
	{
		TargetNode = CastChecked<UK2Node_FormatText>(Objects[0].Get());
		TSharedRef<IPropertyHandle> PropertyHandle = DetailLayout.GetProperty(FName("PinNames"), UK2Node_FormatText::StaticClass());

		IDetailCategoryBuilder& InputsCategory = DetailLayout.EditCategory("Arguments", LOCTEXT("FormatTextDetailsArguments", "Arguments"));

		InputsCategory.AddCustomRow( LOCTEXT("FunctionNewInputArg", "New") )
			[
				SNew(SBox)
				.HAlign(HAlign_Right)
				[
					SNew(SButton)
					.Text(LOCTEXT("FunctionNewInputArg", "New"))
					.OnClicked(this, &FFormatTextDetails::OnAddNewArgument)
					.IsEnabled(this, &FFormatTextDetails::CanEditArguments)
				]
			];

		Layout = MakeShareable( new FFormatTextLayout(TargetNode) );
		InputsCategory.AddCustomBuilder( Layout.ToSharedRef() );
	}

	UPackage::PackageDirtyStateChangedEvent.AddSP(this, &FFormatTextDetails::OnEditorPackageModified);
}
void AddStructToDetails(FName CategoryName, FName PropertyName, IDetailLayoutBuilder& DetailBuilder, bool bInline = true, bool bAdvanced = false)
{
	IDetailCategoryBuilder& Category = DetailBuilder.EditCategory(CategoryName, TEXT(""), ECategoryPriority::Important);
	TSharedPtr<IPropertyHandle> Params = DetailBuilder.GetProperty(PropertyName);
	if (Params.IsValid())
	{
		EPropertyLocation::Type PropertyLocation = bAdvanced ? EPropertyLocation::Advanced : EPropertyLocation::Default;
		if (bInline)
		{
			uint32 NumChildren = 0;
			Params->GetNumChildren(NumChildren);

			// add all collision properties
			for (uint32 ChildIndex = 0; ChildIndex < NumChildren; ++ChildIndex)
			{
				TSharedPtr<IPropertyHandle> ChildProperty = Params->GetChildHandle(ChildIndex);
				Category.AddProperty(ChildProperty, PropertyLocation);
			}
		}
		else
		{
			Category.AddProperty(Params, PropertyLocation);
		}
	}
}
void FPointLightComponentDetails::CustomizeDetails( IDetailLayoutBuilder& DetailBuilder )
{
	TSharedPtr<IPropertyHandle> LightIntensityProperty = DetailBuilder.GetProperty(GET_MEMBER_NAME_CHECKED(ULightComponentBase, Intensity), ULightComponentBase::StaticClass());

	// Inverse squared falloff point lights (the default) are in units of lumens, instead of just being a brightness scale
	LightIntensityProperty->SetInstanceMetaData("UIMin",TEXT("0.0f"));
	LightIntensityProperty->SetInstanceMetaData("UIMax", TEXT("100000.0f"));
	LightIntensityProperty->SetInstanceMetaData("SliderExponent", TEXT("2.0f"));
}
void FBodySetupDetails::CustomizeDetails( IDetailLayoutBuilder& DetailBuilder )
{
	// Customize collision section
	{
		if ( DetailBuilder.GetProperty(GET_MEMBER_NAME_CHECKED(UBodySetup, DefaultInstance))->IsValidHandle() )
		{
			DetailBuilder.GetObjectsBeingCustomized(ObjectsCustomized);
			TSharedPtr<IPropertyHandle> BodyInstanceHandler = DetailBuilder.GetProperty(GET_MEMBER_NAME_CHECKED(UBodySetup, DefaultInstance));

			const bool bInPhat = ObjectsCustomized.Num() && (Cast<USkeletalBodySetup>(ObjectsCustomized[0].Get()) != nullptr);
			if (bInPhat)
			{
				TSharedRef<IPropertyHandle> AsyncEnabled = BodyInstanceHandler->GetChildHandle(GET_MEMBER_NAME_CHECKED(FBodyInstance, bUseAsyncScene)).ToSharedRef();
				AsyncEnabled->MarkHiddenByCustomization();
			}

			BodyInstanceCustomizationHelper = MakeShareable(new FBodyInstanceCustomizationHelper(ObjectsCustomized));
			BodyInstanceCustomizationHelper->CustomizeDetails(DetailBuilder, DetailBuilder.GetProperty(GET_MEMBER_NAME_CHECKED(UBodySetup, DefaultInstance)));

			IDetailCategoryBuilder& CollisionCategory = DetailBuilder.EditCategory("Collision");
			DetailBuilder.HideProperty(BodyInstanceHandler);

			TSharedPtr<IPropertyHandle> CollisionTraceHandler = DetailBuilder.GetProperty(GET_MEMBER_NAME_CHECKED(UBodySetup, CollisionTraceFlag));
			DetailBuilder.HideProperty(CollisionTraceHandler);

			// add physics properties to physics category
			uint32 NumChildren = 0;
			BodyInstanceHandler->GetNumChildren(NumChildren);

			static const FName CollisionCategoryName(TEXT("Collision"));

			// add all properties of this now - after adding 
			for (uint32 ChildIndex=0; ChildIndex < NumChildren; ++ChildIndex)
			{
				TSharedPtr<IPropertyHandle> ChildProperty = BodyInstanceHandler->GetChildHandle(ChildIndex);
				FName CategoryName = FObjectEditorUtils::GetCategoryFName(ChildProperty->GetProperty());
				if (CategoryName == CollisionCategoryName)
				{
					CollisionCategory.AddProperty(ChildProperty);
				}
			}
		}
	}
}
void FBlackboardDataDetails::CustomizeDetails( IDetailLayoutBuilder& DetailLayout )
{
	// First hide all keys
	DetailLayout.HideProperty(TEXT("Keys"));
	DetailLayout.HideProperty(TEXT("ParentKeys"));

	// Now show only the currently selected key
	bool bIsInherited = false;
	int32 CurrentSelection = INDEX_NONE;
	if(OnGetSelectedBlackboardItemIndex.IsBound())
	{
		CurrentSelection = OnGetSelectedBlackboardItemIndex.Execute(bIsInherited);
	}

	if(CurrentSelection >= 0)
	{
		TSharedPtr<IPropertyHandle> KeysHandle = bIsInherited ? DetailLayout.GetProperty(TEXT("ParentKeys")) : DetailLayout.GetProperty(TEXT("Keys"));
		check(KeysHandle.IsValid());
		uint32 NumChildKeys = 0;
		KeysHandle->GetNumChildren(NumChildKeys);
		if((uint32)CurrentSelection < NumChildKeys)
		{
			TSharedPtr<IPropertyHandle> KeyHandle = KeysHandle->GetChildHandle((uint32)CurrentSelection);

			IDetailCategoryBuilder& DetailCategoryBuilder = DetailLayout.EditCategory("Key");
			TSharedPtr<IPropertyHandle> EntryNameProperty = KeyHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FBlackboardEntry, EntryName));
			DetailCategoryBuilder.AddCustomRow(LOCTEXT("EntryNameLabel", "Entry Name"))
			.NameContent()
			[
				EntryNameProperty->CreatePropertyNameWidget()
			]
			.ValueContent()
			[
				SNew(SHorizontalBox)
				.IsEnabled(true)
				+SHorizontalBox::Slot()
				[
					EntryNameProperty->CreatePropertyValueWidget()
				]
			];

#if WITH_EDITORONLY_DATA
// 			TSharedPtr<IPropertyHandle> EntryDescriptionHandle = ElementProperty->GetChildHandle("EntryDescription");
			TSharedPtr<IPropertyHandle> EntryDescriptionHandle = KeyHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FBlackboardEntry, EntryDescription));

			DetailCategoryBuilder.AddProperty(EntryDescriptionHandle);
#endif

			TSharedPtr<IPropertyHandle> KeyTypeProperty = KeyHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FBlackboardEntry, KeyType));
			DetailCategoryBuilder.AddProperty(KeyTypeProperty);

			TSharedPtr<IPropertyHandle> bInstanceSyncedProperty = KeyHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FBlackboardEntry, bInstanceSynced));
			DetailCategoryBuilder.AddProperty(bInstanceSyncedProperty);
		}	
	}
}
void FConfigPropertyHelperDetails::CustomizeDetails(IDetailLayoutBuilder& DetailBuilder)
{
	TSharedPtr<IPropertyHandle> PropertyHandle = DetailBuilder.GetProperty("EditProperty");
	DetailBuilder.HideProperty(PropertyHandle);

	UObject* PropValue;
	PropertyHandle->GetValue(PropValue);
	OriginalProperty = CastChecked<UProperty>(PropValue);

	// Create a runtime UClass with the provided property as the only member. We will use this in the details view for the config hierarchy.
	ConfigEditorPropertyViewClass = NewObject<UClass>(GetTransientPackage(), TEXT("TempConfigEditorUClass"), RF_Public|RF_Standalone);

	// Keep a record of the UProperty we are looking to update
	ConfigEditorCopyOfEditProperty = DuplicateObject<UProperty>(OriginalProperty, ConfigEditorPropertyViewClass, PropValue->GetFName());
	ConfigEditorPropertyViewClass->ClassConfigName = OriginalProperty->GetOwnerClass()->ClassConfigName;
	ConfigEditorPropertyViewClass->SetSuperStruct(UObject::StaticClass());
	ConfigEditorPropertyViewClass->ClassFlags |= (CLASS_DefaultConfig | CLASS_Config);
	ConfigEditorPropertyViewClass->AddCppProperty(ConfigEditorCopyOfEditProperty);
	ConfigEditorPropertyViewClass->Bind();
	ConfigEditorPropertyViewClass->StaticLink(true);
	ConfigEditorPropertyViewClass->AssembleReferenceTokenStream();
	ConfigEditorPropertyViewClass->AddToRoot();
	
	// Cache the CDO for the object
	ConfigEditorPropertyViewCDO = ConfigEditorPropertyViewClass->GetDefaultObject(true);
	ConfigEditorPropertyViewCDO->AddToRoot();

	// Get access to all of the config files where this property is configurable.
	ConfigFilesHandle = DetailBuilder.GetProperty("ConfigFilePropertyObjects");
	DetailBuilder.HideProperty(ConfigFilesHandle);

	// Add the properties to a property table so we can edit these.
	IDetailCategoryBuilder& ConfigHierarchyCategory = DetailBuilder.EditCategory("ConfigHierarchy");
	ConfigHierarchyCategory.AddCustomRow(LOCTEXT("ConfigHierarchy", "ConfigHierarchy"))
	[
		// Create a property table with the values.
		ConstructPropertyTable(DetailBuilder)
	];

	// Listen for changes to the properties, we handle these by updating the ini file associated.
	FCoreUObjectDelegates::OnObjectPropertyChanged.AddSP(this, &FConfigPropertyHelperDetails::OnPropertyValueChanged);
}
void FAndroidSDKSettingsCustomization::BuildSDKPathSection(IDetailLayoutBuilder& DetailLayout)
{
#if PLATFORM_MAC
	IDetailCategoryBuilder& SDKConfigCategory = DetailLayout.EditCategory(TEXT("SDKConfig"));

	// hide the property on Mac only
	TSharedRef<IPropertyHandle> JavaPathProperty = DetailLayout.GetProperty(GET_MEMBER_NAME_CHECKED(UAndroidSDKSettings, JavaPath));
	SDKConfigCategory.AddProperty(JavaPathProperty)
		.Visibility(EVisibility::Hidden);
#endif
}
Example #16
0
void FDeviceProfileDetails::CustomizeDetails(IDetailLayoutBuilder& DetailBuilder)
{
	// Hide all the properties apart from the Console Variables.
	IDetailCategoryBuilder& Category = DetailBuilder.EditCategory("DeviceSettings");

	TSharedPtr<IPropertyHandle> DeviceTypeHandle = DetailBuilder.GetProperty("DeviceType");
	DetailBuilder.HideProperty(DeviceTypeHandle);

	TSharedPtr<IPropertyHandle> MeshLODSettingsHandle = DetailBuilder.GetProperty("MeshLODSettings");
	DetailBuilder.HideProperty(MeshLODSettingsHandle);

	TSharedPtr<IPropertyHandle> TextureLODSettingsHandle = DetailBuilder.GetProperty("TextureLODSettings");
	DetailBuilder.HideProperty(TextureLODSettingsHandle);

	// Setup the parent profile panel
	ParentProfileDetails = MakeShareable(new FDeviceProfileParentPropertyDetails(&DetailBuilder));
	ParentProfileDetails->CreateParentPropertyView();

	// Setup the console variable editor
	ConsoleVariablesDetails = MakeShareable(new FDeviceProfileConsoleVariablesPropertyDetails(&DetailBuilder));
	ConsoleVariablesDetails->CreateConsoleVariablesPropertyView();
}
void FSpriteDetailsCustomization::BuildSpriteSection(IDetailCategoryBuilder& SpriteCategory, IDetailLayoutBuilder& DetailLayout)
{
	// Show other normal properties in the sprite category so that desired ordering doesn't get messed up
	SpriteCategory.AddProperty(GET_MEMBER_NAME_CHECKED(UPaperSprite, SourceUV));
	SpriteCategory.AddProperty(GET_MEMBER_NAME_CHECKED(UPaperSprite, SourceDimension));
	SpriteCategory.AddProperty(GET_MEMBER_NAME_CHECKED(UPaperSprite, SourceTexture));
	SpriteCategory.AddProperty(GET_MEMBER_NAME_CHECKED(UPaperSprite, DefaultMaterial));
	SpriteCategory.AddProperty(GET_MEMBER_NAME_CHECKED(UPaperSprite, Sockets));
	SpriteCategory.AddProperty(GET_MEMBER_NAME_CHECKED(UPaperSprite, PixelsPerUnrealUnit));

	// Show/hide the experimental atlas group support based on whether or not it is enabled
	TSharedPtr<IPropertyHandle> AtlasGroupProperty = DetailLayout.GetProperty(GET_MEMBER_NAME_CHECKED(UPaperSprite, AtlasGroup));
	TAttribute<EVisibility> AtlasGroupPropertyVisibility = TAttribute<EVisibility>::Create(TAttribute<EVisibility>::FGetter::CreateStatic(&FSpriteDetailsCustomization::GetAtlasGroupVisibility));
	SpriteCategory.AddProperty(AtlasGroupProperty, EPropertyLocation::Advanced).Visibility(AtlasGroupPropertyVisibility);

	// Show/hide the custom pivot point based on the pivot mode
	TSharedPtr<IPropertyHandle> PivotModeProperty = DetailLayout.GetProperty(GET_MEMBER_NAME_CHECKED(UPaperSprite, PivotMode));
	TSharedPtr<IPropertyHandle> CustomPivotPointProperty = DetailLayout.GetProperty(GET_MEMBER_NAME_CHECKED(UPaperSprite, CustomPivotPoint));
	TAttribute<EVisibility> CustomPivotPointVisibility = TAttribute<EVisibility>::Create(TAttribute<EVisibility>::FGetter::CreateSP(this, &FSpriteDetailsCustomization::GetCustomPivotVisibility, PivotModeProperty));
	SpriteCategory.AddProperty(PivotModeProperty);
	SpriteCategory.AddProperty(CustomPivotPointProperty).Visibility(CustomPivotPointVisibility);
}
void FPrimitiveComponentDetails::AddCollisionCategory(IDetailLayoutBuilder& DetailBuilder)
{
	if (DetailBuilder.GetProperty(GET_MEMBER_NAME_CHECKED(UPrimitiveComponent, BodyInstance))->IsValidHandle())
	{
		// Collision
		TSharedPtr<IPropertyHandle> BodyInstanceHandler = DetailBuilder.GetProperty(GET_MEMBER_NAME_CHECKED(UPrimitiveComponent, BodyInstance));
		uint32 NumChildren = 0;
		BodyInstanceHandler->GetNumChildren(NumChildren);

		IDetailCategoryBuilder& CollisionCategory = DetailBuilder.EditCategory("Collision");

		// add all collision properties
		for (uint32 ChildIndex = 0; ChildIndex < NumChildren; ++ChildIndex)
		{
			TSharedPtr<IPropertyHandle> ChildProperty = BodyInstanceHandler->GetChildHandle(ChildIndex);
			FString Category = FObjectEditorUtils::GetCategory(ChildProperty->GetProperty());
			if (Category == TEXT("Collision"))
			{
				CollisionCategory.AddProperty(ChildProperty);
			}
		}
	}
}
void FDirectionalLightComponentDetails::CustomizeDetails( IDetailLayoutBuilder& DetailBuilder )
{
    // Grab the Mobility property from SceneComponent
    MobilityProperty = DetailBuilder.GetProperty("Mobility", USceneComponent::StaticClass());

    // Get cascaded shadow map category
    IDetailCategoryBuilder& ShadowMapCategory = DetailBuilder.EditCategory("CascadedShadowMaps", TEXT(""), ECategoryPriority::Default );

    // Add DynamicShadowDistanceMovableLight
    TSharedPtr<IPropertyHandle> MovableShadowRadiusProperty = DetailBuilder.GetProperty("DynamicShadowDistanceMovableLight");
    ShadowMapCategory.AddProperty( MovableShadowRadiusProperty)
    .IsEnabled( TAttribute<bool>( this, &FDirectionalLightComponentDetails::IsLightMovable ) );

    // Add DynamicShadowDistanceStationaryLight
    TSharedPtr<IPropertyHandle> StationaryShadowRadiusProperty = DetailBuilder.GetProperty("DynamicShadowDistanceStationaryLight");
    ShadowMapCategory.AddProperty( StationaryShadowRadiusProperty)
    .IsEnabled( TAttribute<bool>( this, &FDirectionalLightComponentDetails::IsLightStationary ) );

    TSharedPtr<IPropertyHandle> LightIntensityProperty = DetailBuilder.GetProperty("Intensity", ULightComponentBase::StaticClass());
    // Point lights need to override the ui min and max for units of lumens, so we have to undo that
    LightIntensityProperty->GetProperty()->SetMetaData("UIMin",TEXT("0.0f"));
    LightIntensityProperty->GetProperty()->SetMetaData("UIMax",TEXT("20.0f"));
}
void FMacGraphicsSwitchingSettingsDetails::CustomizeDetails( IDetailLayoutBuilder& DetailLayout )
{
	TSharedRef<IPropertyHandle> PreferredRendererPropertyHandle = DetailLayout.GetProperty("RendererID");
	DetailLayout.HideProperty("RendererID");

	bool bAllowMultiGPUs = IMacGraphicsSwitchingModule::Get().AllowMultipleGPUs();
	bool bAllowAutomaticGraphicsSwitching = IMacGraphicsSwitchingModule::Get().AllowAutomaticGraphicsSwitching();
	
	TSharedRef<IPropertyHandle> MultiGPUPropertyHandle = DetailLayout.GetProperty("bUseMultipleRenderers");
	if (!bAllowMultiGPUs)
	{
		MultiGPUPropertyHandle->SetValue(false);
		DetailLayout.HideProperty("bUseMultipleRenderers");
	}
	
	TSharedRef<IPropertyHandle> SwitchingPropertyHandle = DetailLayout.GetProperty("bAllowAutomaticGraphicsSwitching");
	if (!bAllowAutomaticGraphicsSwitching)
	{
		SwitchingPropertyHandle->SetValue(false);
		DetailLayout.HideProperty("bAllowAutomaticGraphicsSwitching");
	}
	
	IDetailCategoryBuilder& AccessorCategory = DetailLayout.EditCategory( "OpenGL" );
	AccessorCategory.AddCustomRow( LOCTEXT("PreferredRenderer", "Preferred Renderer").ToString() )
	.NameContent()
	[
		PreferredRendererPropertyHandle->CreatePropertyNameWidget()
	]
	.ValueContent()
	.MinDesiredWidth(113)
	.MaxDesiredWidth(113)
	[
		SNew(SMacGraphicsSwitchingWidget)
		.bLiveSwitching(false)
		.PreferredRendererPropertyHandle(PreferredRendererPropertyHandle)
	];
}
BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION
void FEnvQueryTest_DotDetails::CustomizeDetails( IDetailLayoutBuilder& DetailLayout )
{
	IDetailCategoryBuilder& DotCategory = DetailLayout.EditCategory(TEXT("Dot"));

	LineAHandle = DetailLayout.GetProperty(GET_MEMBER_NAME_CHECKED(UEnvQueryTest_Dot, LineA));
	FSimpleDelegate OnModeAChangedDelegate = FSimpleDelegate::CreateSP(this, &FEnvQueryTest_DotDetails::OnModeAChanged);
	LineAHandle->SetOnPropertyValueChanged(OnModeAChangedDelegate);
	OnModeAChanged();

	DotCategory.AddProperty(LineAHandle);

	IDetailPropertyRow& LineAFromRow = DotCategory.AddProperty(GET_MEMBER_NAME_CHECKED(UEnvQueryTest_Dot, LineAFrom));
	LineAFromRow.Visibility(TAttribute<EVisibility>::Create(TAttribute<EVisibility>::FGetter::CreateSP(this, &FEnvQueryTest_DotDetails::GetLineASegmentVisibility)));

	IDetailPropertyRow& LineAToRow = DotCategory.AddProperty(GET_MEMBER_NAME_CHECKED(UEnvQueryTest_Dot, LineATo));
	LineAToRow.Visibility(TAttribute<EVisibility>::Create(TAttribute<EVisibility>::FGetter::CreateSP(this, &FEnvQueryTest_DotDetails::GetLineASegmentVisibility)));

	IDetailPropertyRow& LineADirRow = DotCategory.AddProperty(GET_MEMBER_NAME_CHECKED(UEnvQueryTest_Dot, LineADirection));
	LineADirRow.Visibility(TAttribute<EVisibility>::Create(TAttribute<EVisibility>::FGetter::CreateSP(this, &FEnvQueryTest_DotDetails::GetLineADirectionVisibility)));

	LineBHandle = DetailLayout.GetProperty(GET_MEMBER_NAME_CHECKED(UEnvQueryTest_Dot, LineB));
	FSimpleDelegate OnModeBChangedDelegate = FSimpleDelegate::CreateSP(this, &FEnvQueryTest_DotDetails::OnModeBChanged);
	LineBHandle->SetOnPropertyValueChanged(OnModeBChangedDelegate);
	OnModeBChanged();

	DotCategory.AddProperty(LineBHandle);

	IDetailPropertyRow& LineBFromRow = DotCategory.AddProperty(GET_MEMBER_NAME_CHECKED(UEnvQueryTest_Dot, LineBFrom));
	LineBFromRow.Visibility(TAttribute<EVisibility>::Create(TAttribute<EVisibility>::FGetter::CreateSP(this, &FEnvQueryTest_DotDetails::GetLineBSegmentVisibility)));

	IDetailPropertyRow& LineBToRow = DotCategory.AddProperty(GET_MEMBER_NAME_CHECKED(UEnvQueryTest_Dot, LineBTo));
	LineBToRow.Visibility(TAttribute<EVisibility>::Create(TAttribute<EVisibility>::FGetter::CreateSP(this, &FEnvQueryTest_DotDetails::GetLineBSegmentVisibility)));

	IDetailPropertyRow& LineBDirRow = DotCategory.AddProperty(GET_MEMBER_NAME_CHECKED(UEnvQueryTest_Dot, LineBDirection));
	LineBDirRow.Visibility(TAttribute<EVisibility>::Create(TAttribute<EVisibility>::FGetter::CreateSP(this, &FEnvQueryTest_DotDetails::GetLineBDirectionVisibility)));
}
void FMoviePlayerSettingsDetails::CustomizeDetails( IDetailLayoutBuilder& DetailLayout )
{
	IDetailCategoryBuilder& MoviesCategory = DetailLayout.EditCategory("Movies");

	StartupMoviesPropertyHandle = DetailLayout.GetProperty("StartupMovies");

	TSharedRef<FDetailArrayBuilder> StartupMoviesBuilder = MakeShareable( new FDetailArrayBuilder( StartupMoviesPropertyHandle.ToSharedRef() ) );
	StartupMoviesBuilder->OnGenerateArrayElementWidget( FOnGenerateArrayElementWidget::CreateSP(this, &FMoviePlayerSettingsDetails::GenerateArrayElementWidget) );

	MoviesCategory.AddProperty( "bWaitForMoviesToComplete" );
	MoviesCategory.AddProperty( "bMoviesAreSkippable" );

	const bool bForAdvanced = false;
	MoviesCategory.AddCustomBuilder( StartupMoviesBuilder, bForAdvanced );
}
BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION
void FBehaviorDecoratorDetails::CustomizeDetails( IDetailLayoutBuilder& DetailLayout )
{
	FText AbortModeDesc = LOCTEXT("ObserverTitle","Observer aborts");
	PropUtils = &(DetailLayout.GetPropertyUtilities().Get());

	TArray<TWeakObjectPtr<UObject> > EditedObjects;
	DetailLayout.GetObjectsBeingCustomized(EditedObjects);
	
	for (int32 i = 0; i < EditedObjects.Num(); i++)
	{
		UBTDecorator* MyDecorator = Cast<UBTDecorator>(EditedObjects[i].Get());
		if (MyDecorator)
		{
			MyNode = MyDecorator;
			break;
		}
	}
	
	UpdateAllowedAbortModes();
	ModeProperty = DetailLayout.GetProperty(GET_MEMBER_NAME_CHECKED(UBTDecorator, FlowAbortMode));

	// dynamic FlowAbortMode combo
	IDetailCategoryBuilder& FlowCategory = DetailLayout.EditCategory( "FlowControl" );
	IDetailPropertyRow& AbortModeRow = FlowCategory.AddProperty(ModeProperty);
	AbortModeRow.IsEnabled(TAttribute<bool>(this, &FBehaviorDecoratorDetails::GetAbortModeEnabled));
	AbortModeRow.Visibility(TAttribute<EVisibility>::Create(TAttribute<EVisibility>::FGetter::CreateSP(this, &FBehaviorDecoratorDetails::GetModeVisibility)));
	AbortModeRow.CustomWidget()
		.NameContent()
		[
			ModeProperty->CreatePropertyNameWidget(AbortModeDesc)
		]
		.ValueContent()
		[
			SNew(SComboButton)
			.OnGetMenuContent(this, &FBehaviorDecoratorDetails::OnGetAbortModeContent)
 			.ContentPadding(FMargin( 2.0f, 2.0f ))
			.ButtonContent()
			[
				SNew(STextBlock) 
				.Text(this, &FBehaviorDecoratorDetails::GetCurrentAbortModeDesc)
				.Font(IDetailLayoutBuilder::GetDetailFont())
			]
		];
	InitPropertyValues();

}
void FSourceCodeAccessSettingsDetails::CustomizeDetails( IDetailLayoutBuilder& DetailLayout )
{
	TSharedRef<IPropertyHandle> PreferredProviderPropertyHandle = DetailLayout.GetProperty("PreferredAccessor");
	DetailLayout.HideProperty("PreferredAccessor");

	// regenerate accessors list
	Accessors.Empty();

	const int32 FeatureCount = IModularFeatures::Get().GetModularFeatureImplementationCount("SourceCodeAccessor");
	for(int32 FeatureIndex = 0; FeatureIndex < FeatureCount; FeatureIndex++)
	{
		IModularFeature* Feature = IModularFeatures::Get().GetModularFeatureImplementation("SourceCodeAccessor", FeatureIndex);
		check(Feature);

		ISourceCodeAccessor& Accessor = *static_cast<ISourceCodeAccessor*>(Feature);
		if(Accessor.GetFName() != FName("None"))
		{
			Accessors.Add(MakeShareable(new FAccessorItem(Accessor.GetNameText(), Accessor.GetFName())));
		}
	}

	IDetailCategoryBuilder& AccessorCategory = DetailLayout.EditCategory( "Accessor" );
	AccessorCategory.AddCustomRow( LOCTEXT("PreferredAccessor", "Preferred Accessor").ToString() )
	.NameContent()
	[
		PreferredProviderPropertyHandle->CreatePropertyNameWidget()
	]
	.ValueContent()
	.MinDesiredWidth(113)
	.MaxDesiredWidth(113)
	[
		SNew(SComboBox< TSharedPtr<FAccessorItem>>)
		.ToolTipText(LOCTEXT("PreferredAccessorToolTip", "Choose the way to access source code."))
		.OptionsSource(&Accessors)
		.OnSelectionChanged(this, &FSourceCodeAccessSettingsDetails::OnSelectionChanged, PreferredProviderPropertyHandle)
		.ContentPadding(2)
		.OnGenerateWidget(this, &FSourceCodeAccessSettingsDetails::OnGenerateWidget)
		.Content()
		[
			SNew(STextBlock)
			.Text(this, &FSourceCodeAccessSettingsDetails::GetAccessorText)
			.Font( IDetailLayoutBuilder::GetDetailFont() )
		]
	];
}
void FActorComponentDetails::CustomizeDetails( IDetailLayoutBuilder& DetailBuilder )
{
	AddExperimentalWarningCategory(DetailBuilder);

	TSharedPtr<IPropertyHandle> PrimaryTickProperty = DetailBuilder.GetProperty(GET_MEMBER_NAME_CHECKED(UActorComponent, PrimaryComponentTick));

	// Defaults only show tick properties
	if (DetailBuilder.GetDetailsView().HasClassDefaultObject())
	{
		IDetailCategoryBuilder& TickCategory = DetailBuilder.EditCategory("Tick");

		TickCategory.AddProperty(PrimaryTickProperty->GetChildHandle(GET_MEMBER_NAME_CHECKED(FTickFunction, bStartWithTickEnabled)));
		TickCategory.AddProperty(PrimaryTickProperty->GetChildHandle(GET_MEMBER_NAME_CHECKED(FTickFunction, bTickEvenWhenPaused)), EPropertyLocation::Advanced);
		TickCategory.AddProperty(PrimaryTickProperty->GetChildHandle(GET_MEMBER_NAME_CHECKED(FTickFunction, bAllowTickOnDedicatedServer)), EPropertyLocation::Advanced);
	}

	PrimaryTickProperty->MarkHiddenByCustomization();
}
void FTransitionPoseEvaluatorNodeDetails::CustomizeDetails( IDetailLayoutBuilder& DetailBuilder )
{	
	const TArray< TWeakObjectPtr<UObject> >& SelectedObjects = DetailBuilder.GetDetailsView().GetSelectedObjects();
	for (int32 ObjectIndex = 0; (EvaluatorNode == NULL) && (ObjectIndex < SelectedObjects.Num()); ++ObjectIndex)
	{
		const TWeakObjectPtr<UObject>& CurrentObject = SelectedObjects[ObjectIndex];
		if (CurrentObject.IsValid())
		{
			EvaluatorNode = Cast<UAnimGraphNode_TransitionPoseEvaluator>(CurrentObject.Get());
		}
	}

	IDetailCategoryBuilder& PoseCategory = DetailBuilder.EditCategory("Pose", LOCTEXT("PoseCategoryName", "Pose") );
	TSharedPtr<IPropertyHandle> FramesToCachePosePropety = DetailBuilder.GetProperty(TEXT("Node.FramesToCachePose"));

	//@TODO: CONDUIT: try both
	DetailBuilder.HideProperty(FramesToCachePosePropety);
	PoseCategory.AddProperty( FramesToCachePosePropety ).Visibility( TAttribute<EVisibility>( this, &FTransitionPoseEvaluatorNodeDetails::GetFramesToCachePoseVisibility ) );
}
void SheetEquipmentCustomization::CustomizeDetails(IDetailLayoutBuilder& DetailBuilder)
{
    IDetailCategoryBuilder& Category = DetailBuilder.EditCategory("Slots", FText::GetEmpty(), ECategoryPriority::Important);

    //You can get properties using the detailbuilder
    TSharedRef<IPropertyHandle> BaseHandle = DetailBuilder.GetProperty("Equipment");

    if (!BaseHandle->IsValidHandle())
    {
        Category.AddCustomRow(LOCTEXT("Fail", "Fail"))
        .NameContent()
        [
            SNew(STextBlock)
            .Text(LOCTEXT("Fail", "Fail"))
            .Font(IDetailLayoutBuilder::GetDetailFont())
        ];
        return;
    }

    BaseHandle->MarkHiddenByCustomization();

    uint32 num;
    BaseHandle->AsArray()->GetNumElements(num);
    for (uint32 i = 0; i < num; i++)
    {
        FText text = StatEnums::EquipSlots()->GetEnumText(i);
        Category.AddCustomRow(text)
        .NameContent()
        [
            SNew(STextBlock)
            .Text(text)
            .Font(IDetailLayoutBuilder::GetDetailFont())
        ]
        .ValueContent().MinDesiredWidth(500)
        [
            SNew(SHorizontalBox)
            + SHorizontalBox::Slot()
            [
                SNew(SProperty, BaseHandle->AsArray()->GetElement(i)->GetChildHandle("Item"))
                .ShouldDisplayName(false)
            ]];
    }
}
void FSkeletonNotifyDetails::CustomizeDetails( IDetailLayoutBuilder& DetailBuilder )
{
	IDetailCategoryBuilder& Category = DetailBuilder.EditCategory("Skeleton Notify", TEXT("Skeleton Notify") );
	const FSlateFontInfo DetailFontInfo = IDetailLayoutBuilder::GetDetailFont();

	Category.AddProperty("Name").DisplayName( TEXT("Notify Name") );

	TSharedPtr<IPropertyHandle> InPropertyHandle = DetailBuilder.GetProperty("AnimationNames");

	TArray< TWeakObjectPtr<UObject> > SelectedObjects =  DetailBuilder.GetDetailsView().GetSelectedObjects();

	UEditorSkeletonNotifyObj* EdObj = NULL;
	for(int i = 0; i < SelectedObjects.Num(); ++i)
	{
		UObject* Obj = SelectedObjects[0].Get();
		EdObj = Cast<UEditorSkeletonNotifyObj>(Obj);
		if(EdObj)
		{
			break;
		}
	}

	if(EdObj)
	{
		Category.AddCustomRow(TEXT("Animations"))
		.NameContent()
		[
			SNew(STextBlock)
			.ToolTipText(LOCTEXT("Animations_Tooltip", "List of animations that reference this notify"))
			.Text( LOCTEXT("AnimationsLabel","Animations") )
			.Font( DetailFontInfo )
		]
		.ValueContent()
		[
			SNew(SListView<TSharedPtr<FString>>)
			.ListItemsSource(&EdObj->AnimationNames)
			.OnGenerateRow(this, &FSkeletonNotifyDetails::MakeAnimationRow)
		];
	}
}
void FTODAssetDetails::CustomizeDetails(IDetailLayoutBuilder& DetailLayout)
{
	const IDetailsView& DetailView = DetailLayout.GetDetailsView();

	TWeakObjectPtr<UObject> InspectedObject;

	for (TWeakObjectPtr<UObject> inspObj : DetailView.GetSelectedObjects())
	{
		InspectedObject = inspObj;
		break;
	}

	UTODAsset* TODAsset = Cast<UTODAsset>(InspectedObject.Get());

	if (TODAsset)
	{
		for (TFieldIterator<UProperty> PropIt(TODAsset->GetClass()); PropIt; ++PropIt)
		{
			UProperty* prop = *PropIt;
			DetailLayout.HideProperty(prop->GetFName());
		}
	}

	FName CurrentPropertyName = TEXT("SunIntensityCurve");// NAME_None;
	//if (OnGetCurrentProperty.IsBound())
	//{
	//	CurrentPropertyName = OnGetCurrentProperty.Execute();
	//}
	if (CurrentPropertyName != NAME_None)
	{
		TSharedPtr<IPropertyHandle> PropHandle = DetailLayout.GetProperty(CurrentPropertyName);
		check(PropHandle.IsValid());


		IDetailCategoryBuilder& DetailCategoryBuilder = DetailLayout.EditCategory("Property Detail");
		DetailCategoryBuilder.AddProperty(PropHandle);
	}
}
void FPrimitiveComponentDetails::CustomizeDetails( IDetailLayoutBuilder& DetailBuilder )
{
	// Get the objects being customized so we can enable/disable editing of 'Simulate Physics'
	DetailBuilder.GetObjectsBeingCustomized(ObjectsCustomized);

	// See if we are hiding Physics category
	TArray<FString> HideCategories;
	FEditorCategoryUtils::GetClassHideCategories(DetailBuilder.GetDetailsView().GetBaseClass(), HideCategories);

	if(!HideCategories.Contains("Materials"))
	{
		AddMaterialCategory(DetailBuilder);
	}

	TSharedRef<IPropertyHandle> MobilityHandle = DetailBuilder.GetProperty(GET_MEMBER_NAME_CHECKED(UPrimitiveComponent, Mobility), USceneComponent::StaticClass());
	MobilityHandle->SetToolTipText(LOCTEXT("PrimitiveMobilityTooltip", "Mobility for primitive components controls how they can be modified in game and therefore how they interact with lighting and physics.\n● A movable primitive component can be changed in game, but requires dynamic lighting and shadowing from lights which have a large performance cost.\n● A static primitive component can't be changed in game, but can have its lighting baked, which allows rendering to be very efficient."));


	if(!HideCategories.Contains("Physics"))
	{
		AddPhysicsCategory(DetailBuilder);
	}

	if (!HideCategories.Contains("Collision"))
	{
		AddCollisionCategory(DetailBuilder);
	}

	if(!HideCategories.Contains("Lighting"))
	{
		AddLightingCategory(DetailBuilder);
	}

	AddAdvancedSubCategory( DetailBuilder, "Rendering", "TextureStreaming" );
	AddAdvancedSubCategory( DetailBuilder, "Rendering", "LOD");
}