void FSlateSoundStructCustomization::CustomizeStructHeader(TSharedRef<IPropertyHandle> StructPropertyHandle, FDetailWidgetRow& HeaderRow, IStructCustomizationUtils& StructCustomizationUtils)
{
	TSharedPtr<IPropertyHandle> ResourceObjectProperty = StructPropertyHandle->GetChildHandle(TEXT("ResourceObject"));
	check(ResourceObjectProperty.IsValid());

	TArray<void*> StructPtrs;
	StructPropertyHandle->AccessRawData(StructPtrs);
	for(auto It = StructPtrs.CreateConstIterator(); It; ++It)
	{
		FSlateSound* const SlateSound = reinterpret_cast<FSlateSound*>(*It);
		SlateSoundStructs.Add(SlateSound);
	}

	HeaderRow
	.NameContent()
	[
		StructPropertyHandle->CreatePropertyNameWidget()
	]
	.ValueContent()
	.MinDesiredWidth(250.0f)
	[
		SNew(SObjectPropertyEntryBox)
		.PropertyHandle(ResourceObjectProperty)
		.AllowedClass(USoundBase::StaticClass())
		.OnObjectChanged(this, &FSlateSoundStructCustomization::OnObjectChanged)
	];
}
BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION
void FAIDataProviderValueDetails::CustomizeHeader(TSharedRef<class IPropertyHandle> StructPropertyHandle, class FDetailWidgetRow& HeaderRow, IPropertyTypeCustomizationUtils& StructCustomizationUtils)
{
	DataBindingProperty = StructPropertyHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FAIDataProviderValue, DataBinding));
	DataFieldProperty = StructPropertyHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FAIDataProviderValue, DataField));
	DefaultValueProperty = StructPropertyHandle->GetChildHandle(TEXT("DefaultValue"));

	DataBindingProperty->SetOnPropertyValueChanged(FSimpleDelegate::CreateSP(this, &FAIDataProviderValueDetails::OnBindingChanged));
	
	TArray<void*> StructPtrs;
	StructPropertyHandle->AccessRawData(StructPtrs);
	DataPtr = (StructPtrs.Num() == 1) ? reinterpret_cast<FAIDataProviderValue*>(StructPtrs[0]) : nullptr;
	OnBindingChanged();

	TSharedRef<SWidget> DefPropWidget = DefaultValueProperty->CreatePropertyValueWidget();
	DefPropWidget->SetVisibility(TAttribute<EVisibility>::Create(TAttribute<EVisibility>::FGetter::CreateSP(this, &FAIDataProviderValueDetails::GetDefaultValueVisibility)));

	HeaderRow
	.NameContent()
	[
		StructPropertyHandle->CreatePropertyNameWidget()
	]
	.ValueContent()
	.VAlign(VAlign_Center)
	.MinDesiredWidth(300.0f)
	[
		SNew(SHorizontalBox)
		+ SHorizontalBox::Slot()
		.Padding(0.0f, 2.0f, 5.0f, 2.0f)
		[
			SNew(STextBlock)
			.Text(this, &FAIDataProviderValueDetails::GetValueDesc)
			.Font(IDetailLayoutBuilder::GetDetailFont())
			.Visibility(TAttribute<EVisibility>::Create(TAttribute<EVisibility>::FGetter::CreateSP(this, &FAIDataProviderValueDetails::GetBindingDescVisibility)))
		]
		+ SHorizontalBox::Slot()
		.Padding(0.0f, 2.0f, 5.0f, 2.0f)
		[
			DefPropWidget
		]
	];
}
void FVehicleTransmissionDataCustomization::CustomizeChildren(TSharedRef<class IPropertyHandle> StructPropertyHandle, class IDetailChildrenBuilder& StructBuilder, IPropertyTypeCustomizationUtils& StructCustomizationUtils)
{
	// copy all transmision instances I'm accessing right now
	TArray<void*> StructPtrs;
	StructPropertyHandle->AccessRawData(StructPtrs);
	
	if (StructPtrs.Num() == 1)
	{
		SelectedTransmission = (FVehicleTransmissionData *)StructPtrs[0];
	}
	else
	{
		SelectedTransmission = NULL;
	}


	uint32 NumChildren = 0;
	StructPropertyHandle->GetNumChildren(NumChildren);

	FName GearsSetupGroupName = TEXT("GearsSetup");
	FText GearsSetupGroupLabel = LOCTEXT("GearSetupLabel", "Gears Setup");
	IDetailGroup * GearSetupGroup = NULL;
	
	for (uint32 ChildIdx = 0; ChildIdx < NumChildren; ++ChildIdx)
	{
		TSharedRef<IPropertyHandle> ChildProperty = StructPropertyHandle->GetChildHandle(ChildIdx).ToSharedRef();
		const FString PropertyName = ChildProperty->GetProperty() ? ChildProperty->GetProperty()->GetName() : TEXT("");

		if (PropertyName == TEXT("ForwardGears") || PropertyName == TEXT("NeutralGearUpRatio") || PropertyName == TEXT("ReverseGearRatio"))
		{
			if (GearSetupGroup == NULL)
			{
				GearSetupGroup = &StructBuilder.AddChildGroup(GearsSetupGroupName, GearsSetupGroupLabel);
				BuildColumnsHeaderHelper(StructPropertyHandle, StructBuilder.AddChildContent(GearsSetupGroupLabel));
			}

			//determine which gear we're showing
			EGearType GearType = ForwardGear;
			if (PropertyName == TEXT("NeutralGearUpRatio"))
			{
				GearType = NeutralGear;
			}
			else if
			(PropertyName == TEXT("ReverseGearRatio"))
			{
				GearType = ReverseGear;
			}
						
			if (GearType == ForwardGear)
			{
				TSharedRef<FDetailArrayBuilder> GearsArrayBuilder = MakeShareable(new FDetailArrayBuilder(ChildProperty, false));
				GearsArrayBuilder->OnGenerateArrayElementWidget(FOnGenerateArrayElementWidget::CreateSP(this, &FVehicleTransmissionDataCustomization::CreateGearUIDelegate));
				StructBuilder.AddChildCustomBuilder(GearsArrayBuilder);
			}
			else
			{
				const FText PropertyNameText = FText::FromString(PropertyName);
				CreateGearUIHelper(StructBuilder.AddChildContent(PropertyNameText), PropertyNameText, ChildProperty, GearType);
			}


		}
		else
		{	//Add all other properties
			StructBuilder.AddChildProperty(ChildProperty);
		}
	}

}
void FKeyStructCustomization::CustomizeStructHeader( TSharedRef<class IPropertyHandle> StructPropertyHandle, class FDetailWidgetRow& HeaderRow, IStructCustomizationUtils& StructCustomizationUtils )
{
    PropertyHandle = StructPropertyHandle;

    TArray<void*> StructPtrs;
    StructPropertyHandle->AccessRawData(StructPtrs);
    check(StructPtrs.Num() != 0);
    const FKey& SelectedKey = *(FKey*)StructPtrs[0];

    bool bMultipleValues = false;
    for (int32 StructPtrIndex = 1; StructPtrIndex < StructPtrs.Num(); ++StructPtrIndex)
    {
        if (*(FKey*)StructPtrs[StructPtrIndex] != SelectedKey)
        {
            bMultipleValues = true;
            break;
        }
    }

    TSharedPtr<FKey> InitialSelectedItem;
    TArray<FKey> AllKeys;
    EKeys::GetAllKeys(AllKeys);

    for (FKey Key : AllKeys)
    {
        TSharedPtr<FKey> InputKey = MakeShareable(new FKey(Key));
        InputKeys.Add(InputKey);
        if (Key == SelectedKey)
        {
            InitialSelectedItem = InputKey;
        }
    }

    // create struct header
    HeaderRow.NameContent()
    [
        StructPropertyHandle->CreatePropertyNameWidget()
    ]
    .ValueContent()
    .MinDesiredWidth(125.0f)
    .MaxDesiredWidth(325.0f)
    [
        SNew(SHorizontalBox)

        + SHorizontalBox::Slot()
        .FillWidth(1.0f)
        [
            // text box
            SNew(SComboBox< TSharedPtr<FKey> >)
            .OptionsSource(&InputKeys)
            .InitiallySelectedItem(InitialSelectedItem)
            .OnGenerateWidget(this, &FKeyStructCustomization::OnGenerateComboWidget)
            .OnSelectionChanged(this, &FKeyStructCustomization::OnSelectionChanged)
            .Content()
            [
                SAssignNew(TextBlock, STextBlock)
                .Text(bMultipleValues ? LOCTEXT("MultipleValues", "Multiple Values") : SelectedKey.GetDisplayName())
                .Font(StructCustomizationUtils.GetRegularFont())
            ]
        ]
    ];
}