// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved. #include "DetailCustomizationsPrivatePCH.h" #include "PostProcessSettingsCustomization.h" #include "ObjectEditorUtils.h" #include "LightPropagationVolumeBlendable.h" #include "SWidgetSwitcher.h" #include "Classes/Engine/BlendableInterface.h" #define LOCTEXT_NAMESPACE "PostProcessSettingsCustomization" void FPostProcessSettingsCustomization::CustomizeChildren( TSharedRef StructPropertyHandle, class IDetailChildrenBuilder& StructBuilder, IPropertyTypeCustomizationUtils& StructCustomizationUtils ) { TMap CategoryNameToGroupMap; uint32 NumChildren = 0; FPropertyAccess::Result Result = StructPropertyHandle->GetNumChildren(NumChildren); UProperty* Prop = StructPropertyHandle->GetProperty(); UStructProperty* StructProp = Cast(Prop); // a category with this name should be one level higher, should be "PostProcessSettings" FName ClassName = StructProp->Struct->GetFName(); if( Result == FPropertyAccess::Success && NumChildren > 0) { for( uint32 ChildIndex = 0; ChildIndex < NumChildren; ++ChildIndex ) { TSharedPtr ChildHandle = StructPropertyHandle->GetChildHandle( ChildIndex ); if( ChildHandle.IsValid() && ChildHandle->GetProperty() ) { UProperty* Property = ChildHandle->GetProperty(); FName Category = FObjectEditorUtils::GetCategoryFName( Property ); if(Category == ClassName) { // Some elements should be outside of the categories, they need to specify the struct nama as category StructBuilder.AddChildProperty( ChildHandle.ToSharedRef() ); } else { IDetailGroup* Group = CategoryNameToGroupMap.FindRef( Category ); if( !Group ) { Group = &StructBuilder.AddChildGroup( Category, FText::FromString( FName::NameToDisplayString( Category.ToString(), false ) ) ); CategoryNameToGroupMap.Add( Category, Group ); } Group->AddPropertyRow( ChildHandle.ToSharedRef() ); } } } } } void FPostProcessSettingsCustomization::CustomizeHeader( TSharedRef StructPropertyHandle, class FDetailWidgetRow& HeaderRow, IPropertyTypeCustomizationUtils& StructCustomizationUtils ) { HeaderRow.NameContent() [ StructPropertyHandle->CreatePropertyNameWidget() ]; HeaderRow.ValueContent() [ StructPropertyHandle->CreatePropertyValueWidget() ]; } void FWeightedBlendableCustomization::AddDirectAsset(TSharedRef StructPropertyHandle, UPackage* Package, TSharedPtr Weight, TSharedPtr Value) { Weight->SetValue(1.0f); { TArray Objects; StructPropertyHandle->GetOuterObjects(Objects); TArray Values; for(TArray::TConstIterator It = Objects.CreateConstIterator(); It; It++) { UObject* Obj = *It; const UObject* NewObj = NewObject(Obj); FString Str = NewObj->GetPathName(); Values.Add(Str); } Value->SetPerObjectValues(Values); } } void FWeightedBlendableCustomization::AddIndirectAsset(TSharedPtr Weight) { Weight->SetValue(1.0f); } EVisibility FWeightedBlendableCustomization::IsWeightVisible(TSharedPtr Weight) const { float WeightValue = 1.0f; Weight->GetValue(WeightValue); return (WeightValue >= 0) ? EVisibility::Visible : EVisibility::Hidden; } FText FWeightedBlendableCustomization::GetDirectAssetName(TSharedPtr Value) const { UObject* RefObject = 0; Value->GetValue(RefObject); check(RefObject); return FText::FromString(RefObject->GetFullName()); } FReply FWeightedBlendableCustomization::JumpToDirectAsset(TSharedPtr Value) { UObject* RefObject = 0; Value->GetValue(RefObject); FAssetEditorManager::Get().OpenEditorForAsset(RefObject); return FReply::Handled(); } TSharedRef FWeightedBlendableCustomization::GenerateContentWidget(TSharedRef StructPropertyHandle, UPackage* Package, TSharedPtr Weight, TSharedPtr Value) { FMenuBuilder MenuBuilder(true, NULL); { /* for(TObjectIterator It; It; ++It) { if(It->IsChildOf(UFactory::StaticClass())) if(It->IsChildOf(UBlendableInterface::StaticClass())) */ // todo: iterate through all UFactories that create UClasses with UBlendableInterface { FUIAction Direct2(FExecuteAction::CreateSP(this, &FWeightedBlendableCustomization::AddDirectAsset, StructPropertyHandle, Package, Weight, Value)); MenuBuilder.AddMenuEntry(LOCTEXT("Blendable_DirectAsset2", "Light Propagation Volume Blendable"), LOCTEXT("Blendable_DirectAsset2h", "references Light Propagation Volume Blendable (owned by the containing object)"), FSlateIcon(), Direct2); } MenuBuilder.AddMenuSeparator(); FUIAction Indirect(FExecuteAction::CreateSP(this, &FWeightedBlendableCustomization::AddIndirectAsset, Weight)); MenuBuilder.AddMenuEntry(LOCTEXT("Blendable_IndirectAsset", "Asset reference"), LOCTEXT("Blendable_IndirectAsseth", "reference a Blendable asset (owned by a content package), e.g. material with Post Process domain"), FSlateIcon(), Indirect); } TSharedRef Switcher = SNew(SWidgetSwitcher) .WidgetIndex(this, &FWeightedBlendableCustomization::ComputeSwitcherIndex, StructPropertyHandle, Package, Weight, Value); Switcher->AddSlot() [ SNew(SComboButton) .ButtonContent() [ SNew(STextBlock) .Text(LOCTEXT("Blendable_ChooseElement", "Choose")) ] .ContentPadding(FMargin(6.0, 2.0)) .MenuContent() [ MenuBuilder.MakeWidget() ] ]; Switcher->AddSlot() [ SNew(SButton) .ContentPadding(FMargin(0,0)) .Text(this, &FWeightedBlendableCustomization::GetDirectAssetName, Value) .OnClicked(this, &FWeightedBlendableCustomization::JumpToDirectAsset, Value) ]; Switcher->AddSlot() [ SNew(SObjectPropertyEntryBox) .PropertyHandle(Value) ]; return Switcher; } int32 FWeightedBlendableCustomization::ComputeSwitcherIndex(TSharedRef StructPropertyHandle, UPackage* Package, TSharedPtr Weight, TSharedPtr Value) const { float WeightValue = 1.0f; UObject* RefObject = 0; Weight->GetValue(WeightValue); Value->GetValue(RefObject); if(RefObject) { UPackage* PropPackage = RefObject->GetOutermost(); return (PropPackage == Package) ? 1 : 2; } else { return (WeightValue < 0.0f) ? 0 : 2; } } void FWeightedBlendableCustomization::CustomizeChildren( TSharedRef StructPropertyHandle, class IDetailChildrenBuilder& StructBuilder, IPropertyTypeCustomizationUtils& StructCustomizationUtils ) { // we don't have children but this is a pure virtual so we need to override } void FWeightedBlendableCustomization::CustomizeHeader( TSharedRef StructPropertyHandle, class FDetailWidgetRow& HeaderRow, IPropertyTypeCustomizationUtils& StructCustomizationUtils ) { TSharedPtr SharedWeightProp; { TSharedPtr ChildHandle = StructPropertyHandle->GetChildHandle(FName(TEXT("Weight"))); if (ChildHandle.IsValid() && ChildHandle->GetProperty()) { SharedWeightProp = ChildHandle; } } TSharedPtr SharedValueProp; { TSharedPtr ChildHandle = StructPropertyHandle->GetChildHandle(FName(TEXT("Object"))); if (ChildHandle.IsValid() && ChildHandle->GetProperty()) { SharedValueProp = ChildHandle; } } float WeightValue = 1.0f; UObject* RefObject = 0; SharedWeightProp->GetValue(WeightValue); SharedValueProp->GetValue(RefObject); UPackage* StructPackage = 0; { const TSharedPtr ParentHandle = StructPropertyHandle->GetParentHandle(); TArray Objects; StructPropertyHandle->GetOuterObjects(Objects); for (TArray::TConstIterator It = Objects.CreateConstIterator(); It; It++) { UObject* ref = *It; if(StructPackage) { // does this mean we have to deal with multiple levels? The code here is not ready for that check(StructPackage == ref->GetOutermost()); } StructPackage = ref->GetOutermost(); } } HeaderRow.NameContent() [ SNew(SHorizontalBox) .Visibility(this, &FWeightedBlendableCustomization::IsWeightVisible, SharedWeightProp) +SHorizontalBox::Slot() [ SNew(SBox) .MinDesiredWidth(44.0f) .MaxDesiredWidth(44.0f) [ SharedWeightProp->CreatePropertyValueWidget() ] ] ]; HeaderRow.ValueContent() [ SNew(SHorizontalBox) + SHorizontalBox::Slot() [ GenerateContentWidget(StructPropertyHandle, StructPackage, SharedWeightProp, SharedValueProp) ] ]; } #undef LOCTEXT_NAMESPACE