2020-07-30 16:57:04 -04:00
// Copyright Epic Games, Inc. All Rights Reserved.
# include "MetasoundLiteralDescriptionDetailCustomization.h"
# include "CoreMinimal.h"
# include "Delegates/Delegate.h"
# include "DetailCategoryBuilder.h"
# include "DetailLayoutBuilder.h"
# include "DetailWidgetRow.h"
# include "IDetailChildrenBuilder.h"
# include "IDetailGroup.h"
# include "Layout/Visibility.h"
2020-08-13 19:07:41 -04:00
# include "MetasoundFrontend.h"
2021-01-13 10:48:59 -04:00
# include "MetasoundFrontendDocument.h"
2020-08-13 19:07:41 -04:00
# include "MetasoundFrontendRegistries.h"
2020-07-30 16:57:04 -04:00
# include "Misc/AssertionMacros.h"
# include "Misc/Attribute.h"
# include "PropertyEditorDelegates.h"
# include "PropertyHandle.h"
# include "Templates/Casts.h"
# include "Templates/SharedPointer.h"
# include "Widgets/Text/STextBlock.h"
2020-08-13 19:07:41 -04:00
# include "PropertyCustomizationHelpers.h"
2021-02-09 14:46:26 -04:00
# include "Slate/Public/Widgets/SToolTip.h"
2020-07-30 16:57:04 -04:00
# define LOCTEXT_NAMESPACE "MetasoundEditor"
namespace Metasound
{
namespace Editor
{
2021-01-13 10:48:59 -04:00
TSharedPtr < IPropertyHandle > GetLiteralHandleForType ( TSharedRef < IPropertyHandle > StructPropertyHandle , EMetasoundFrontendLiteralType LiteralType )
2020-07-30 16:57:04 -04:00
{
switch ( LiteralType )
{
2021-01-13 10:48:59 -04:00
case EMetasoundFrontendLiteralType : : Bool :
2020-07-30 16:57:04 -04:00
{
2021-01-13 10:48:59 -04:00
return StructPropertyHandle - > GetChildHandle ( GET_MEMBER_NAME_CHECKED ( FMetasoundFrontendLiteral , AsBool ) ) ;
2020-07-30 16:57:04 -04:00
}
2021-01-13 10:48:59 -04:00
case EMetasoundFrontendLiteralType : : Float :
2020-07-30 16:57:04 -04:00
{
2021-01-13 10:48:59 -04:00
return StructPropertyHandle - > GetChildHandle ( GET_MEMBER_NAME_CHECKED ( FMetasoundFrontendLiteral , AsFloat ) ) ;
2020-07-30 16:57:04 -04:00
}
2021-01-13 10:48:59 -04:00
case EMetasoundFrontendLiteralType : : Integer :
2020-07-30 16:57:04 -04:00
{
2021-01-13 10:48:59 -04:00
return StructPropertyHandle - > GetChildHandle ( GET_MEMBER_NAME_CHECKED ( FMetasoundFrontendLiteral , AsInteger ) ) ;
2020-07-30 16:57:04 -04:00
}
2021-01-13 10:48:59 -04:00
case EMetasoundFrontendLiteralType : : String :
2020-07-30 16:57:04 -04:00
{
2021-01-13 10:48:59 -04:00
return StructPropertyHandle - > GetChildHandle ( GET_MEMBER_NAME_CHECKED ( FMetasoundFrontendLiteral , AsString ) ) ;
2020-07-30 16:57:04 -04:00
}
2021-01-13 10:48:59 -04:00
case EMetasoundFrontendLiteralType : : UObject :
2020-08-13 19:07:41 -04:00
{
2021-01-13 10:48:59 -04:00
return StructPropertyHandle - > GetChildHandle ( GET_MEMBER_NAME_CHECKED ( FMetasoundFrontendLiteral , AsUObject ) ) ;
2020-08-13 19:07:41 -04:00
}
2021-01-13 10:48:59 -04:00
case EMetasoundFrontendLiteralType : : UObjectArray :
2020-08-13 19:07:41 -04:00
{
2021-01-13 10:48:59 -04:00
return StructPropertyHandle - > GetChildHandle ( GET_MEMBER_NAME_CHECKED ( FMetasoundFrontendLiteral , AsUObjectArray ) ) ;
2020-08-13 19:07:41 -04:00
}
2021-01-13 10:48:59 -04:00
case EMetasoundFrontendLiteralType : : None :
2020-07-30 16:57:04 -04:00
default :
2021-01-13 10:48:59 -04:00
static_assert ( static_cast < int32 > ( EMetasoundFrontendLiteralType : : Invalid ) = = 7 , " Possible missing case coverage for EMetasoundFrontendLiteralType " ) ;
2020-07-30 16:57:04 -04:00
return TSharedPtr < IPropertyHandle > ( ) ;
}
}
TSharedPtr < IPropertyHandle > GetActiveLiteralHandle ( TSharedRef < IPropertyHandle > StructPropertyHandle , TSharedRef < IPropertyHandle > TypeEnumHandle )
{
2021-01-13 10:48:59 -04:00
uint8 Value = static_cast < uint8 > ( EMetasoundFrontendLiteralType : : None ) ;
2020-07-30 16:57:04 -04:00
if ( TypeEnumHandle - > GetValue ( Value ) = = FPropertyAccess : : Result : : Success )
{
2021-01-13 10:48:59 -04:00
const EMetasoundFrontendLiteralType LiteralType = static_cast < EMetasoundFrontendLiteralType > ( Value ) ;
2020-07-30 16:57:04 -04:00
return GetLiteralHandleForType ( StructPropertyHandle , LiteralType ) ;
}
return TSharedPtr < IPropertyHandle > ( ) ;
}
2021-01-13 10:48:59 -04:00
bool IsLiteralTypeActive ( TSharedRef < IPropertyHandle > TypeEnumHandle , EMetasoundFrontendLiteralType LiteralType )
2020-07-30 16:57:04 -04:00
{
2021-01-13 10:48:59 -04:00
uint8 Value = static_cast < uint8 > ( EMetasoundFrontendLiteralType : : None ) ;
2020-07-30 16:57:04 -04:00
TypeEnumHandle - > GetValue ( Value ) ;
return Value = = static_cast < uint8 > ( LiteralType ) ;
}
} // namespace Editor
} // namespace Metasound
2021-01-13 10:48:59 -04:00
void FMetasoundFrontendLiteralDetailCustomization : : CustomizeHeader ( TSharedRef < IPropertyHandle > StructPropertyHandle , FDetailWidgetRow & HeaderRow , IPropertyTypeCustomizationUtils & StructCustomizationUtils )
2020-07-30 16:57:04 -04:00
{
}
2021-01-13 10:48:59 -04:00
void FMetasoundFrontendLiteralDetailCustomization : : CustomizeChildren ( TSharedRef < IPropertyHandle > StructPropertyHandle , IDetailChildrenBuilder & ChildBuilder , IPropertyTypeCustomizationUtils & StructCustomizationUtils )
2020-07-30 16:57:04 -04:00
{
2021-01-13 10:48:59 -04:00
TSharedRef < IPropertyHandle > TypeEnumHandle = StructPropertyHandle - > GetChildHandle ( GET_MEMBER_NAME_CHECKED ( FMetasoundFrontendLiteral , Type ) ) . ToSharedRef ( ) ;
2020-07-30 16:57:04 -04:00
2020-08-13 19:07:41 -04:00
FName OwningDataTypeName ;
UClass * OwningDataTypeClass = nullptr ;
2021-01-13 10:48:59 -04:00
EMetasoundFrontendLiteralType PreferredLiteralType = EMetasoundFrontendLiteralType : : None ;
2020-08-13 19:07:41 -04:00
// Grab the preferred uclass for the owning data type.
2021-01-13 10:48:59 -04:00
TSharedPtr < IPropertyHandle > InputDescription = StructPropertyHandle - > GetParentHandle ( ) - > GetParentHandle ( ) - > GetParentHandle ( ) ;
2020-08-13 19:07:41 -04:00
// TODO: Ensure that StructPropertyHandle is an FMetasoundInputDescription.
if ( InputDescription )
{
2021-01-13 10:48:59 -04:00
TSharedPtr < IPropertyHandle > DataTypeNameHandle = InputDescription - > GetChildHandle ( GET_MEMBER_NAME_CHECKED ( FMetasoundFrontendClassInput , TypeName ) ) ;
2020-08-13 19:07:41 -04:00
if ( DataTypeNameHandle )
{
DataTypeNameHandle - > GetValue ( OwningDataTypeName ) ;
FMetasoundFrontendRegistryContainer * Registry = FMetasoundFrontendRegistryContainer : : Get ( ) ;
OwningDataTypeClass = Registry - > GetLiteralUClassForDataType ( OwningDataTypeName ) ;
PreferredLiteralType = Metasound : : Frontend : : GetMetasoundLiteralType ( Registry - > GetDesiredLiteralTypeForDataType ( OwningDataTypeName ) ) ;
}
}
2020-07-30 16:57:04 -04:00
struct FTypeEditorInfo
{
2021-01-13 10:48:59 -04:00
EMetasoundFrontendLiteralType LiteralType ;
2020-08-13 19:07:41 -04:00
TSharedRef < IPropertyHandle > TypeEnumHandle ;
2020-07-30 16:57:04 -04:00
TSharedPtr < IPropertyHandle > PropertyHandle ;
FText DisplayName ;
2020-08-13 19:07:41 -04:00
UClass * OwningDataTypeUClass ;
2021-02-09 14:46:26 -04:00
FName OwningDataTypeName ;
TSharedRef < SWidget > CreateEnumWidget ( const TSharedPtr < const Metasound : : Frontend : : IEnumDataTypeInterface > & EnumInterface ) const
{
auto RemoveNameSpace = [ ] ( const FString & InString ) - > FString
{
FString Namespace , EnumName ;
InString . Split ( TEXT ( " :: " ) , & Namespace , & EnumName ) ;
return EnumName ;
} ;
auto GetAll = [ EnumInterface , RemoveNameSpace ] ( TArray < TSharedPtr < FString > > & OutStrings , TArray < TSharedPtr < SToolTip > > & OutTooltips , TArray < bool > & )
{
for ( const Metasound : : Frontend : : IEnumDataTypeInterface : : FGenericInt32Entry & i : EnumInterface - > GetAllEntries ( ) )
{
OutTooltips . Emplace ( SNew ( SToolTip ) . Text ( i . Tooltip ) ) ;
// Trim the namespace off for display.
OutStrings . Emplace ( MakeShared < FString > ( RemoveNameSpace ( i . Name . GetPlainNameString ( ) ) ) ) ;
}
} ;
auto GetValue = [ EnumInterface , Prop = PropertyHandle , RemoveNameSpace ] ( ) - > FString
{
int32 IntValue ;
if ( Prop - > GetValue ( IntValue ) )
{
if ( TOptional < FName > Result = EnumInterface - > ToName ( IntValue ) )
{
return RemoveNameSpace ( Result - > GetPlainNameString ( ) ) ;
}
UE_LOG ( LogTemp , Warning , TEXT ( " Failed to Get Valid Value for Property '%s' with Value of '%d' " ) ,
* GetNameSafe ( Prop - > GetProperty ( ) ) , IntValue ) ;
}
return { } ;
} ;
auto SelectedValue = [ EnumInterface , Prop = PropertyHandle ] ( const FString & InSelected )
{
FString FullyQualifiedName = FString : : Printf ( TEXT ( " %s::%s " ) , * EnumInterface - > GetNamespace ( ) . GetPlainNameString ( ) , * InSelected ) ;
TOptional < int32 > Result = EnumInterface - > ToValue ( * FullyQualifiedName ) ;
if ( ensure ( Result ) )
{
Prop - > SetValue ( * Result ) ;
}
} ;
return PropertyCustomizationHelpers : : MakePropertyComboBox (
nullptr ,
FOnGetPropertyComboBoxStrings : : CreateLambda ( GetAll ) ,
FOnGetPropertyComboBoxValue : : CreateLambda ( GetValue ) ,
FOnPropertyComboBoxValueSelected : : CreateLambda ( SelectedValue )
) ;
}
2020-08-13 19:07:41 -04:00
TSharedRef < SWidget > CreatePropertyValueWidget ( bool bDisplayDefaultPropertyButtons = true ) const
{
2021-01-13 10:48:59 -04:00
if ( LiteralType = = EMetasoundFrontendLiteralType : : UObject )
2020-08-13 19:07:41 -04:00
{
auto ValidateAsset = [ CachedDataTypeUClass = OwningDataTypeUClass ] ( const UObject * InObject , FText & OutReason ) - > bool
{
UClass * SelectedObjectClass = InObject - > GetClass ( ) ;
return CachedDataTypeUClass & & SelectedObjectClass & & SelectedObjectClass - > IsChildOf ( CachedDataTypeUClass ) ;
} ;
auto CommitAsset = [ CachedLiteralType = LiteralType , CachedPropertyHandle = PropertyHandle , CachedEnumHandle = TypeEnumHandle , CachedDataTypeUClass = OwningDataTypeUClass ] ( const FAssetData & InAssetData ) - > void
{
// if we've hit this code, the presumption is that the datatype for this parameter has already defined a corresponding UClass that can be used to set it.
ensureAlways ( CachedDataTypeUClass & & CachedDataTypeUClass ! = UObject : : StaticClass ( ) ) ;
UObject * InObject = InAssetData . GetAsset ( ) ;
CachedPropertyHandle - > SetValue ( InObject ) ;
// If this asset selector was set to no asset, clear out the literal description.
if ( InObject )
{
2021-01-13 10:48:59 -04:00
CachedEnumHandle - > SetValue ( static_cast < uint8 > ( EMetasoundFrontendLiteralType : : UObject ) ) ;
2020-08-13 19:07:41 -04:00
}
else
{
2021-01-13 10:48:59 -04:00
CachedEnumHandle - > SetValue ( static_cast < uint8 > ( EMetasoundFrontendLiteralType : : None ) ) ;
2020-08-13 19:07:41 -04:00
}
} ;
auto GetAssetPath = [ CachedPropertyHandle = PropertyHandle ] ( ) - > FString
{
UObject * Obj = nullptr ;
CachedPropertyHandle - > GetValue ( Obj ) ;
return Obj ! = nullptr ? Obj - > GetPathName ( ) : FString ( ) ;
} ;
// TODO: get the UFactory corresponding to this datatype's UClass.
TArray < UFactory * > FactoriesToUse ;
return SNew ( SObjectPropertyEntryBox )
. ObjectPath_Lambda ( GetAssetPath )
. AllowedClass ( OwningDataTypeUClass )
// .OnShouldSetAsset_Lambda(ValidateAsset)
. OnObjectChanged_Lambda ( CommitAsset )
. AllowClear ( false )
. DisplayUseSelected ( true )
. DisplayBrowse ( true )
. DisplayThumbnail ( true )
. NewAssetFactories ( FactoriesToUse ) ;
}
2021-02-09 14:46:26 -04:00
else if ( LiteralType = = EMetasoundFrontendLiteralType : : Integer )
{
// Check if this is an Enum.
if ( TSharedPtr < const Metasound : : Frontend : : IEnumDataTypeInterface > EnumInterface =
FMetasoundFrontendRegistryContainer : : Get ( ) - > GetEnumInterfaceForDataType ( OwningDataTypeName ) )
{
return CreateEnumWidget ( EnumInterface ) ;
}
// Fall back to regular widget if its not.
return PropertyHandle - > CreatePropertyValueWidget ( ) ;
}
2021-01-13 10:48:59 -04:00
else if ( LiteralType = = EMetasoundFrontendLiteralType : : UObjectArray )
2020-08-13 19:07:41 -04:00
{
// TODO: Implement.
return SNullWidget : : NullWidget ;
}
else
{
return PropertyHandle - > CreatePropertyValueWidget ( ) ;
}
}
2020-07-30 16:57:04 -04:00
} ;
2021-01-13 10:48:59 -04:00
static_assert ( static_cast < int32 > ( EMetasoundFrontendLiteralType : : Invalid ) = = 7 , " Possible missing property descriptor for literal customization display " ) ;
2020-07-30 16:57:04 -04:00
const TArray < FTypeEditorInfo > TypePropertyInfo =
{
FTypeEditorInfo
{
2021-01-13 10:48:59 -04:00
EMetasoundFrontendLiteralType : : Bool ,
2020-08-13 19:07:41 -04:00
TypeEnumHandle ,
2021-01-13 10:48:59 -04:00
StructPropertyHandle - > GetChildHandle ( GET_MEMBER_NAME_CHECKED ( FMetasoundFrontendLiteral , AsBool ) ) ,
2020-08-13 19:07:41 -04:00
LOCTEXT ( " Metasound_LiteralDisplayNameBool " , " Bool " ) ,
2021-02-09 14:46:26 -04:00
nullptr ,
OwningDataTypeName
2020-07-30 16:57:04 -04:00
} ,
FTypeEditorInfo
{
2021-01-13 10:48:59 -04:00
EMetasoundFrontendLiteralType : : Integer ,
2020-08-13 19:07:41 -04:00
TypeEnumHandle ,
2021-01-13 10:48:59 -04:00
StructPropertyHandle - > GetChildHandle ( GET_MEMBER_NAME_CHECKED ( FMetasoundFrontendLiteral , AsInteger ) ) ,
2020-08-13 19:07:41 -04:00
LOCTEXT ( " Metasound_LiteralDisplayNameInteger " , " Int32 " ) ,
2021-02-09 14:46:26 -04:00
nullptr ,
OwningDataTypeName
2020-07-30 16:57:04 -04:00
} ,
FTypeEditorInfo
{
2021-01-13 10:48:59 -04:00
EMetasoundFrontendLiteralType : : Float ,
2020-08-13 19:07:41 -04:00
TypeEnumHandle ,
2021-01-13 10:48:59 -04:00
StructPropertyHandle - > GetChildHandle ( GET_MEMBER_NAME_CHECKED ( FMetasoundFrontendLiteral , AsFloat ) ) ,
2020-08-13 19:07:41 -04:00
LOCTEXT ( " Metasound_LiteralDisplayNameFloat " , " Float " ) ,
2021-02-09 14:46:26 -04:00
nullptr ,
OwningDataTypeName
2020-07-30 16:57:04 -04:00
} ,
FTypeEditorInfo
{
2021-01-13 10:48:59 -04:00
EMetasoundFrontendLiteralType : : String ,
2020-08-13 19:07:41 -04:00
TypeEnumHandle ,
2021-01-13 10:48:59 -04:00
StructPropertyHandle - > GetChildHandle ( GET_MEMBER_NAME_CHECKED ( FMetasoundFrontendLiteral , AsString ) ) ,
2020-08-13 19:07:41 -04:00
LOCTEXT ( " Metasound_LiteralDisplayNameString " , " String " ) ,
2021-02-09 14:46:26 -04:00
nullptr ,
OwningDataTypeName
2020-08-13 19:07:41 -04:00
} ,
FTypeEditorInfo
{
2021-01-13 10:48:59 -04:00
EMetasoundFrontendLiteralType : : UObject ,
2020-08-13 19:07:41 -04:00
TypeEnumHandle ,
2021-01-13 10:48:59 -04:00
StructPropertyHandle - > GetChildHandle ( GET_MEMBER_NAME_CHECKED ( FMetasoundFrontendLiteral , AsUObject ) ) ,
2020-08-13 19:07:41 -04:00
LOCTEXT ( " Metasound_LiteralDisplayNameUObject " , " UObject " ) ,
2021-02-09 14:46:26 -04:00
OwningDataTypeClass ,
OwningDataTypeName
2020-08-13 19:07:41 -04:00
} ,
FTypeEditorInfo
{
2021-01-13 10:48:59 -04:00
EMetasoundFrontendLiteralType : : UObjectArray ,
2020-08-13 19:07:41 -04:00
TypeEnumHandle ,
2021-01-13 10:48:59 -04:00
StructPropertyHandle - > GetChildHandle ( GET_MEMBER_NAME_CHECKED ( FMetasoundFrontendLiteral , AsUObjectArray ) ) ,
2020-08-13 19:07:41 -04:00
LOCTEXT ( " Metasound_LiteralDisplayNameUObjectArray " , " UObjectArray " ) ,
2021-02-09 14:46:26 -04:00
OwningDataTypeClass ,
OwningDataTypeName
}
2020-07-30 16:57:04 -04:00
} ;
for ( const FTypeEditorInfo & Info : TypePropertyInfo )
{
ChildBuilder . AddCustomRow ( StructPropertyHandle - > GetPropertyDisplayName ( ) )
. NameContent ( )
[
SNew ( SHorizontalBox )
+ SHorizontalBox : : Slot ( )
. FillWidth ( 0.5f )
. Padding ( 1.0f , 0.0f , 0.0f , 0.0f )
. VAlign ( VAlign_Center )
. HAlign ( HAlign_Right )
[
SNew ( STextBlock )
. Font ( IDetailLayoutBuilder : : GetDetailFont ( ) )
. Text ( LOCTEXT ( " Metasound_LiteralDefault " , " Default " ) )
. ToolTipText ( TAttribute < FText > : : Create ( [ StructPropertyHandle , TypeEnumHandle ] ( )
{
TSharedPtr < IPropertyHandle > VisibleHandle = Metasound : : Editor : : GetActiveLiteralHandle ( StructPropertyHandle , TypeEnumHandle ) ;
if ( VisibleHandle . IsValid ( ) )
{
return VisibleHandle - > GetToolTipText ( ) ;
}
return FText : : GetEmpty ( ) ;
} ) )
]
]
. ValueContent ( )
. MinDesiredWidth ( 120.0f )
[
SNew ( SHorizontalBox )
+ SHorizontalBox : : Slot ( )
. FillWidth ( 0.5f )
. Padding ( 1.0f , 0.0f , 0.0f , 0.0f )
. VAlign ( VAlign_Center )
[
2020-08-13 19:07:41 -04:00
Info . CreatePropertyValueWidget ( )
2020-07-30 16:57:04 -04:00
]
]
2020-08-13 19:07:41 -04:00
. Visibility ( TAttribute < EVisibility > : : Create ( [ PreferredLiteralType , LiteralType = Info . LiteralType ] ( )
2020-07-30 16:57:04 -04:00
{
2020-08-13 19:07:41 -04:00
const bool bIsLiteralActive = LiteralType = = PreferredLiteralType ;
2020-07-30 16:57:04 -04:00
return bIsLiteralActive ? EVisibility : : Visible : EVisibility : : Hidden ;
} ) ) ;
}
}
2021-01-13 10:48:59 -04:00
# undef LOCTEXT_NAMESPACE // MetasoundEditor