2021-03-19 15:10:57 -04:00
// Copyright Epic Games, Inc. All Rights Reserved.
# include "MetasoundNodeDetailCustomization.h"
2021-04-06 01:41:29 -04:00
# include "Components/AudioComponent.h"
2021-03-19 15:10:57 -04:00
# include "Containers/Set.h"
# include "CoreMinimal.h"
# include "Delegates/Delegate.h"
# include "DetailCategoryBuilder.h"
# include "DetailLayoutBuilder.h"
# include "DetailWidgetRow.h"
# include "Framework/Notifications/NotificationManager.h"
# include "IDetailChildrenBuilder.h"
# include "IDetailGroup.h"
# include "Internationalization/Text.h"
# include "MetasoundAssetBase.h"
2021-04-07 02:59:10 -04:00
# include "MetasoundDataReference.h"
2021-03-19 15:10:57 -04:00
# include "MetasoundEditorGraphBuilder.h"
# include "MetasoundEditorGraphNode.h"
# include "MetasoundEditorGraphInputNodes.h"
2021-11-07 23:43:01 -05:00
# include "MetasoundEditorGraphSchema.h"
2021-03-25 23:46:38 -04:00
# include "MetasoundEditorModule.h"
2021-03-19 15:10:57 -04:00
# include "MetasoundFrontend.h"
# include "MetasoundFrontendController.h"
# include "MetasoundFrontendRegistries.h"
# include "MetasoundUObjectRegistry.h"
# include "PropertyCustomizationHelpers.h"
# include "PropertyEditorDelegates.h"
# include "PropertyHandle.h"
# include "PropertyRestriction.h"
# include "SlateCore/Public/Styling/SlateColor.h"
2021-11-07 23:43:01 -05:00
# include "SMetasoundActionMenu.h"
2021-04-07 02:59:10 -04:00
# include "SMetasoundGraphNode.h"
2021-11-07 23:43:01 -05:00
# include "SSearchableComboBox.h"
2021-03-19 15:10:57 -04:00
# include "Templates/Casts.h"
# include "Templates/SharedPointer.h"
# include "UObject/WeakObjectPtr.h"
# include "UObject/WeakObjectPtrTemplates.h"
2021-03-25 23:46:38 -04:00
# include "Widgets/Images/SImage.h"
# include "Widgets/Input/SButton.h"
2021-03-19 15:10:57 -04:00
# include "Widgets/Input/SCheckBox.h"
# include "Widgets/Input/SMultiLineEditableTextBox.h"
# include "Widgets/Input/STextComboBox.h"
# include "Widgets/Notifications/SNotificationList.h"
# include "Widgets/SToolTip.h"
# include "Widgets/SWidget.h"
# include "Widgets/Text/STextBlock.h"
2021-04-02 03:03:27 -04:00
# define LOCTEXT_NAMESPACE "MetaSoundEditor"
2021-03-19 15:10:57 -04:00
namespace Metasound
{
namespace Editor
{
2021-10-25 20:05:28 -04:00
namespace MemberCustomizationPrivate
2021-03-19 15:10:57 -04:00
{
static const FText InputNameText = LOCTEXT ( " Input_Name " , " Input Name " ) ;
2021-09-13 14:14:37 -04:00
static const FText InputDisplayNameText = LOCTEXT ( " InputDisplay_Name " , " Input Display Name " ) ;
2021-03-19 15:10:57 -04:00
static const FText OutputNameText = LOCTEXT ( " Output_Name " , " Output Name " ) ;
2021-09-13 14:14:37 -04:00
static const FText OutputDisplayNameText = LOCTEXT ( " OutputDisplay_Name " , " Output Display Name " ) ;
2021-03-19 15:10:57 -04:00
2021-04-06 21:02:21 -04:00
/** Set of input types which are valid registered types, but should
* not show up as an input type option in the MetaSound editor . */
static const TSet < FName > HiddenInputTypeNames =
{
" Audio:Mono " ,
2021-04-13 12:55:34 -04:00
" Audio:Stereo "
2021-04-06 21:02:21 -04:00
} ;
2021-10-25 20:05:28 -04:00
} // namespace MemberCustomizationPrivate
2021-10-12 21:21:22 -04:00
FMetasoundFloatLiteralCustomization : : ~ FMetasoundFloatLiteralCustomization ( )
{
if ( FloatLiteral . IsValid ( ) )
{
FloatLiteral - > OnClampInputChanged . Remove ( OnClampInputChangedDelegateHandle ) ;
FloatLiteral - > OnRangeChanged . Remove ( InputWidgetOnRangeChangedDelegateHandle ) ;
}
}
void FMetasoundFloatLiteralCustomization : : CustomizeLiteral ( UMetasoundEditorGraphInputLiteral & InLiteral , TSharedPtr < IPropertyHandle > InDefaultValueHandle )
{
check ( InputCategoryBuilder ) ;
UMetasoundEditorGraphInputFloat * InputFloat = Cast < UMetasoundEditorGraphInputFloat > ( & InLiteral ) ;
if ( ! ensure ( InputFloat ) )
{
return ;
}
FloatLiteral = InputFloat ;
if ( IDetailPropertyRow * Row = InputCategoryBuilder - > AddExternalObjectProperty ( TArray < UObject * > ( { InputFloat } ) , GET_MEMBER_NAME_CHECKED ( UMetasoundEditorGraphInputFloat , ClampDefault ) ) )
{
// If clamping or using slider, clamp default value to given range
2021-11-18 14:37:34 -05:00
if ( InputFloat - > ClampDefault | | InputFloat - > InputWidgetType ! = EMetasoundInputWidget : : None )
2021-10-12 21:21:22 -04:00
{
FVector2D Range = InputFloat - > GetRange ( ) ;
InDefaultValueHandle - > SetInstanceMetaData ( " ClampMin " , FString : : Printf ( TEXT ( " %f " ) , Range . X ) ) ;
InDefaultValueHandle - > SetInstanceMetaData ( " ClampMax " , FString : : Printf ( TEXT ( " %f " ) , Range . Y ) ) ;
}
else // Stop clamping
{
InDefaultValueHandle - > SetInstanceMetaData ( " ClampMin " , " " ) ;
InDefaultValueHandle - > SetInstanceMetaData ( " ClampMax " , " " ) ;
}
InputFloat - > OnClampInputChanged . Remove ( OnClampInputChangedDelegateHandle ) ;
OnClampInputChangedDelegateHandle = InputFloat - > OnClampInputChanged . AddLambda ( [ this ] ( bool ClampInput )
{
if ( FloatLiteral . IsValid ( ) )
{
FloatLiteral - > OnClampInputChanged . Remove ( OnClampInputChangedDelegateHandle ) ;
2021-11-22 15:55:50 -05:00
if ( FMetasoundAssetBase * MetasoundAsset = Metasound : : IMetasoundUObjectRegistry : : Get ( ) . GetObjectAsAssetBase ( FloatLiteral - > GetOutermostObject ( ) ) )
2021-10-12 21:21:22 -04:00
{
2021-11-22 15:55:50 -05:00
MetasoundAsset - > SetSynchronizationRequired ( ) ;
2021-10-12 21:21:22 -04:00
}
}
} ) ;
}
if ( IDetailPropertyRow * Row = InputCategoryBuilder - > AddExternalObjectProperty ( TArray < UObject * > ( { InputFloat } ) , GET_MEMBER_NAME_CHECKED ( UMetasoundEditorGraphInputFloat , Range ) ) )
{
TSharedPtr < IPropertyHandle > RangeHandle = Row - > GetPropertyHandle ( ) ;
if ( RangeHandle . IsValid ( ) )
{
TWeakObjectPtr < UMetasoundEditorGraphInput > Input = Cast < UMetasoundEditorGraphInput > ( FloatLiteral - > GetOuter ( ) ) ;
FSimpleDelegate UpdateDocumentInput = FSimpleDelegate : : CreateLambda ( [ Input ] ( )
{
if ( Input . IsValid ( ) )
{
2021-11-18 16:49:57 -05:00
if ( UMetasoundEditorGraphInputLiteral * InputLiteral = Input - > Literal )
{
InputLiteral - > UpdateDocumentInputLiteral ( ) ;
}
2021-10-12 21:21:22 -04:00
}
} ) ;
RangeHandle - > SetOnPropertyValueChanged ( UpdateDocumentInput ) ;
RangeHandle - > SetOnChildPropertyValueChanged ( UpdateDocumentInput ) ;
// If the range is changed, we want to update these details in case we now need to clamp the value
if ( ! InputWidgetOnRangeChangedDelegateHandle . IsValid ( ) )
{
InputWidgetOnRangeChangedDelegateHandle = InputFloat - > OnRangeChanged . AddLambda ( [ this ] ( FVector2D Range )
{
if ( FloatLiteral . IsValid ( ) )
{
FloatLiteral - > OnRangeChanged . Remove ( InputWidgetOnRangeChangedDelegateHandle ) ;
2021-11-22 15:55:50 -05:00
if ( FMetasoundAssetBase * MetasoundAsset = Metasound : : IMetasoundUObjectRegistry : : Get ( ) . GetObjectAsAssetBase ( FloatLiteral - > GetOutermostObject ( ) ) )
2021-10-12 21:21:22 -04:00
{
2021-11-22 15:55:50 -05:00
MetasoundAsset - > SetSynchronizationRequired ( ) ;
2021-10-12 21:21:22 -04:00
}
}
} ) ;
}
}
}
2021-03-23 17:55:31 -04:00
}
void FMetasoundInputBoolDetailCustomization : : CacheProxyData ( TSharedPtr < IPropertyHandle > ProxyHandle )
{
DataTypeName = FName ( ) ;
2021-10-25 20:05:28 -04:00
const FString * MetadataDataTypeName = ProxyHandle - > GetInstanceMetaData ( MemberCustomizationPrivate : : DataTypeNameIdentifier ) ;
2021-03-23 17:55:31 -04:00
if ( ensure ( MetadataDataTypeName ) )
{
DataTypeName = * * MetadataDataTypeName ;
}
}
FText FMetasoundInputBoolDetailCustomization : : GetPropertyNameOverride ( ) const
{
2021-04-07 02:59:10 -04:00
if ( DataTypeName = = Metasound : : GetMetasoundDataTypeName < Metasound : : FTrigger > ( ) )
2021-03-23 17:55:31 -04:00
{
return LOCTEXT ( " TriggerInput_SimulateTitle " , " Simulate " ) ;
}
return FText : : GetEmpty ( ) ;
}
TSharedRef < SWidget > FMetasoundInputBoolDetailCustomization : : CreateStructureWidget ( TSharedPtr < IPropertyHandle > & StructPropertyHandle ) const
{
using namespace Frontend ;
if ( FMetasoundFrontendRegistryContainer * Registry = FMetasoundFrontendRegistryContainer : : Get ( ) )
{
TSharedPtr < IPropertyHandle > ValueProperty = StructPropertyHandle - > GetChildHandle ( GET_MEMBER_NAME_CHECKED ( FMetasoundEditorGraphInputBoolRef , Value ) ) ;
if ( ValueProperty . IsValid ( ) )
{
// Not a trigger, so just display as underlying literal type (bool)
2021-04-07 02:59:10 -04:00
if ( DataTypeName ! = Metasound : : GetMetasoundDataTypeName < Metasound : : FTrigger > ( ) )
2021-03-23 17:55:31 -04:00
{
return ValueProperty - > CreatePropertyValueWidget ( ) ;
}
2021-04-07 02:59:10 -04:00
TArray < UObject * > OuterObjects ;
ValueProperty - > GetOuterObjects ( OuterObjects ) ;
for ( UObject * Object : OuterObjects )
{
if ( UMetasoundEditorGraphInputLiteral * Literal = Cast < UMetasoundEditorGraphInputLiteral > ( Object ) )
{
return SMetasoundGraphNode : : CreateTriggerSimulationWidget ( * Literal ) ;
}
}
2021-03-23 17:55:31 -04:00
}
}
return SNullWidget : : NullWidget ;
2021-03-19 15:10:57 -04:00
}
void FMetasoundInputIntDetailCustomization : : CacheProxyData ( TSharedPtr < IPropertyHandle > ProxyHandle )
{
DataTypeName = FName ( ) ;
2021-10-25 20:05:28 -04:00
const FString * MetadataDataTypeName = ProxyHandle - > GetInstanceMetaData ( MemberCustomizationPrivate : : DataTypeNameIdentifier ) ;
2021-03-19 15:10:57 -04:00
if ( ensure ( MetadataDataTypeName ) )
{
DataTypeName = * * MetadataDataTypeName ;
}
}
TSharedRef < SWidget > FMetasoundInputIntDetailCustomization : : CreateStructureWidget ( TSharedPtr < IPropertyHandle > & StructPropertyHandle ) const
{
using namespace Frontend ;
if ( FMetasoundFrontendRegistryContainer * Registry = FMetasoundFrontendRegistryContainer : : Get ( ) )
{
TSharedPtr < IPropertyHandle > ValueProperty = StructPropertyHandle - > GetChildHandle ( GET_MEMBER_NAME_CHECKED ( FMetasoundEditorGraphInputIntRef , Value ) ) ;
if ( ValueProperty . IsValid ( ) )
{
2021-08-19 09:59:27 -04:00
TSharedPtr < const IEnumDataTypeInterface > EnumInterface = IDataTypeRegistry : : Get ( ) . GetEnumInterfaceForDataType ( DataTypeName ) ;
2021-03-19 15:10:57 -04:00
// Not an enum, so just display as underlying type (int32)
if ( ! EnumInterface . IsValid ( ) )
{
return ValueProperty - > CreatePropertyValueWidget ( ) ;
}
auto GetAll = [ Interface = EnumInterface ] ( TArray < TSharedPtr < FString > > & OutStrings , TArray < TSharedPtr < SToolTip > > & OutTooltips , TArray < bool > & )
{
for ( const IEnumDataTypeInterface : : FGenericInt32Entry & i : Interface - > GetAllEntries ( ) )
{
OutTooltips . Emplace ( SNew ( SToolTip ) . Text ( i . Tooltip ) ) ;
OutStrings . Emplace ( MakeShared < FString > ( i . DisplayName . ToString ( ) ) ) ;
}
} ;
auto GetValue = [ Interface = EnumInterface , Prop = ValueProperty ] ( )
{
int32 IntValue ;
if ( Prop - > GetValue ( IntValue ) ! = FPropertyAccess : : Success )
{
IntValue = Interface - > GetDefaultValue ( ) ;
2021-03-31 00:23:34 -04:00
UE_LOG ( LogMetasoundEditor , Warning , TEXT ( " Failed to read int Property '%s', defaulting. " ) , * GetNameSafe ( Prop - > GetProperty ( ) ) ) ;
2021-03-19 15:10:57 -04:00
}
if ( TOptional < IEnumDataTypeInterface : : FGenericInt32Entry > Result = Interface - > FindByValue ( IntValue ) )
{
return Result - > DisplayName . ToString ( ) ;
}
2021-03-31 00:23:34 -04:00
UE_LOG ( LogMetasoundEditor , Warning , TEXT ( " Failed to resolve int value '%d' to a valid enum value for enum '%s' " ) ,
2021-03-19 15:10:57 -04:00
IntValue , * Interface - > GetNamespace ( ) . ToString ( ) ) ;
// Return default (should always succeed as we can't have empty Enums and we must have a default).
return Interface - > FindByValue ( Interface - > GetDefaultValue ( ) ) - > DisplayName . ToString ( ) ;
} ;
auto SelectedValue = [ Interface = EnumInterface , Prop = ValueProperty ] ( const FString & InSelected )
{
TOptional < IEnumDataTypeInterface : : FGenericInt32Entry > Found =
Interface - > FindEntryBy ( [ TextSelected = FText : : FromString ( InSelected ) ] ( const IEnumDataTypeInterface : : FGenericInt32Entry & i )
{
return i . DisplayName . EqualTo ( TextSelected ) ;
} ) ;
if ( Found )
{
// Only save the changes if its different and we can read the old value to check that.
int32 CurrentValue ;
bool bReadCurrentValue = Prop - > GetValue ( CurrentValue ) = = FPropertyAccess : : Success ;
if ( ( bReadCurrentValue & & CurrentValue ! = Found - > Value ) | | ! bReadCurrentValue )
{
ensure ( Prop - > SetValue ( Found - > Value ) = = FPropertyAccess : : Success ) ;
}
}
else
{
2021-03-31 00:23:34 -04:00
UE_LOG ( LogMetasoundEditor , Warning , TEXT ( " Failed to Set Valid Value for Property '%s' with Value of '%s', writing default. " ) ,
2021-03-19 15:10:57 -04:00
* GetNameSafe ( Prop - > GetProperty ( ) ) , * InSelected ) ;
ensure ( Prop - > SetValue ( Interface - > GetDefaultValue ( ) ) = = FPropertyAccess : : Success ) ;
}
} ;
return PropertyCustomizationHelpers : : MakePropertyComboBox (
nullptr ,
FOnGetPropertyComboBoxStrings : : CreateLambda ( GetAll ) ,
FOnGetPropertyComboBoxValue : : CreateLambda ( GetValue ) ,
FOnPropertyComboBoxValueSelected : : CreateLambda ( SelectedValue )
) ;
}
}
return SNullWidget : : NullWidget ;
}
void FMetasoundInputObjectDetailCustomization : : CacheProxyData ( TSharedPtr < IPropertyHandle > ProxyHandle )
{
ProxyGenClass . Reset ( ) ;
2021-10-25 20:05:28 -04:00
const FString * MetadataProxyGenClass = ProxyHandle - > GetInstanceMetaData ( MemberCustomizationPrivate : : ProxyGeneratorClassNameIdentifier ) ;
2021-03-19 15:10:57 -04:00
TSharedPtr < IPropertyHandle > MetadataHandle = ProxyHandle - > GetParentHandle ( ) ;
if ( ! ensure ( MetadataProxyGenClass ) )
{
return ;
}
const FName ClassName = FName ( * MetadataProxyGenClass ) ;
for ( TObjectIterator < UClass > ClassIt ; ClassIt ; + + ClassIt )
{
UClass * Class = * ClassIt ;
if ( ! Class - > IsNative ( ) )
{
continue ;
}
2021-11-07 23:43:01 -05:00
if ( Class - > HasAnyClassFlags ( CLASS_Deprecated | CLASS_NewerVersionExists ) )
2021-03-19 15:10:57 -04:00
{
continue ;
}
if ( ClassIt - > GetFName ( ) ! = ClassName )
{
continue ;
}
ProxyGenClass = * ClassIt ;
return ;
}
ensureMsgf ( false , TEXT ( " Failed to find ProxyGeneratorClass. Class not set " ) ) ;
}
TSharedRef < SWidget > FMetasoundInputObjectDetailCustomization : : CreateStructureWidget ( TSharedPtr < IPropertyHandle > & StructPropertyHandle ) const
{
TSharedPtr < IPropertyHandle > PropertyHandle = StructPropertyHandle - > GetChildHandle ( GET_MEMBER_NAME_CHECKED ( FMetasoundEditorGraphInputObjectRef , Object ) ) ;
2021-11-07 23:43:01 -05:00
const IMetasoundEditorModule & EditorModule = FModuleManager : : GetModuleChecked < IMetasoundEditorModule > ( " MetaSoundEditor " ) ;
auto FilterAsset = [ InEditorModule = & EditorModule , InProxyGenClass = ProxyGenClass ] ( const FAssetData & InAsset )
2021-03-19 15:10:57 -04:00
{
2021-11-07 23:43:01 -05:00
if ( InProxyGenClass . IsValid ( ) )
2021-03-19 15:10:57 -04:00
{
2021-11-07 23:43:01 -05:00
if ( UClass * Class = InAsset . GetClass ( ) )
2021-03-19 15:10:57 -04:00
{
2021-11-07 23:43:01 -05:00
if ( InEditorModule - > IsExplicitProxyClass ( * InProxyGenClass . Get ( ) ) )
{
return Class ! = InProxyGenClass . Get ( ) ;
}
return ! Class - > IsChildOf ( InProxyGenClass . Get ( ) ) ;
2021-03-19 15:10:57 -04:00
}
}
2021-11-07 23:43:01 -05:00
return true ;
} ;
auto ValidateAsset = [ FilterAsset ] ( const FAssetData & InAsset )
{
return ! FilterAsset ( InAsset ) ;
2021-03-19 15:10:57 -04:00
} ;
auto GetAssetPath = [ PropertyHandle = PropertyHandle ] ( )
{
UObject * Object = nullptr ;
if ( PropertyHandle - > GetValue ( Object ) = = FPropertyAccess : : Success )
{
return Object - > GetPathName ( ) ;
}
return FString ( ) ;
} ;
return SNew ( SObjectPropertyEntryBox )
2021-04-05 19:26:15 -04:00
. AllowClear ( true )
2021-08-18 15:16:57 -04:00
. AllowedClass ( ProxyGenClass . Get ( ) )
2021-03-19 15:10:57 -04:00
. DisplayBrowse ( true )
. DisplayThumbnail ( true )
2021-08-18 15:16:57 -04:00
. DisplayUseSelected ( true )
. NewAssetFactories ( PropertyCustomizationHelpers : : GetNewAssetFactoriesForClasses ( { ProxyGenClass . Get ( ) } ) )
. ObjectPath_Lambda ( GetAssetPath )
. OnShouldFilterAsset_Lambda ( FilterAsset )
. OnShouldSetAsset_Lambda ( ValidateAsset )
. PropertyHandle ( PropertyHandle ) ;
2021-03-19 15:10:57 -04:00
}
2021-03-23 17:55:31 -04:00
TSharedRef < SWidget > FMetasoundInputArrayDetailCustomizationBase : : CreateNameWidget ( TSharedPtr < IPropertyHandle > StructPropertyHandle ) const
{
const FText PropertyName = GetPropertyNameOverride ( ) ;
if ( ! PropertyName . IsEmpty ( ) )
{
return SNew ( STextBlock )
. Font ( IDetailLayoutBuilder : : GetDetailFont ( ) )
. Text ( PropertyName ) ;
}
return SNew ( STextBlock )
2021-10-25 20:05:28 -04:00
. Text ( MemberCustomizationPrivate : : DefaultPropertyText )
2021-03-23 17:55:31 -04:00
. Font ( IDetailLayoutBuilder : : GetDetailFont ( ) ) ;
}
2021-03-19 15:10:57 -04:00
TSharedRef < SWidget > FMetasoundInputArrayDetailCustomizationBase : : CreateValueWidget ( TSharedPtr < IPropertyHandleArray > ParentArrayProperty , TSharedPtr < IPropertyHandle > StructPropertyHandle , bool bIsInArray ) const
{
2021-03-23 17:55:31 -04:00
TSharedRef < SWidget > ValueWidget = CreateStructureWidget ( StructPropertyHandle ) ;
2021-03-19 15:10:57 -04:00
if ( ! bIsInArray )
{
2021-03-23 17:55:31 -04:00
return ValueWidget ;
2021-03-19 15:10:57 -04:00
}
TSharedPtr < IPropertyHandle > StructPropertyPtr = StructPropertyHandle ;
FExecuteAction InsertAction = FExecuteAction : : CreateLambda ( [ ParentArrayProperty , StructPropertyPtr ]
{
const int32 ArrayIndex = StructPropertyPtr . IsValid ( ) ? StructPropertyPtr - > GetIndexInArray ( ) : INDEX_NONE ;
if ( ParentArrayProperty . IsValid ( ) & & ArrayIndex > = 0 )
{
ParentArrayProperty - > Insert ( ArrayIndex ) ;
}
} ) ;
FExecuteAction DeleteAction = FExecuteAction : : CreateLambda ( [ ParentArrayProperty , StructPropertyPtr ]
{
const int32 ArrayIndex = StructPropertyPtr . IsValid ( ) ? StructPropertyPtr - > GetIndexInArray ( ) : INDEX_NONE ;
if ( ParentArrayProperty . IsValid ( ) & & ArrayIndex > = 0 )
{
ParentArrayProperty - > DeleteItem ( ArrayIndex ) ;
}
} ) ;
FExecuteAction DuplicateAction = FExecuteAction : : CreateLambda ( [ ParentArrayProperty , StructPropertyPtr ]
{
const int32 ArrayIndex = StructPropertyPtr . IsValid ( ) ? StructPropertyPtr - > GetIndexInArray ( ) : INDEX_NONE ;
if ( ParentArrayProperty . IsValid ( ) & & ArrayIndex > = 0 )
{
ParentArrayProperty - > DuplicateItem ( ArrayIndex ) ;
}
} ) ;
return SNew ( SHorizontalBox )
+ SHorizontalBox : : Slot ( )
2021-10-25 20:05:28 -04:00
. FillWidth ( 1.0f )
2021-03-19 15:10:57 -04:00
. Padding ( 1.0f , 0.0f , 0.0f , 0.0f )
. VAlign ( VAlign_Center )
[
2021-03-23 17:55:31 -04:00
ValueWidget
2021-03-19 15:10:57 -04:00
]
+ SHorizontalBox : : Slot ( )
2021-10-25 20:05:28 -04:00
. AutoWidth ( )
. Padding ( - 6.0f , 0.0f , 0.0f , 0.0f ) // Negative padding intentional on the left to bring the dropdown closer to the other buttons
2021-03-19 15:10:57 -04:00
. VAlign ( VAlign_Center )
[
PropertyCustomizationHelpers : : MakeInsertDeleteDuplicateButton ( InsertAction , DeleteAction , DuplicateAction )
] ;
}
void FMetasoundInputArrayDetailCustomizationBase : : CustomizeChildren ( TSharedRef < IPropertyHandle > StructPropertyHandle , IDetailChildrenBuilder & ChildBuilder , IPropertyTypeCustomizationUtils & StructCustomizationUtils )
{
bool bIsInArray = false ;
TSharedPtr < IPropertyHandleArray > ParentArrayProperty ;
TSharedPtr < IPropertyHandle > ProxyProperty = StructPropertyHandle ;
{
TSharedPtr < IPropertyHandle > ParentProperty = ProxyProperty - > GetParentHandle ( ) ;
if ( ProxyProperty . IsValid ( ) & & ParentProperty . IsValid ( ) )
{
ParentArrayProperty = ParentProperty - > AsArray ( ) ;
if ( ParentArrayProperty . IsValid ( ) )
{
ProxyProperty = ParentProperty ;
bIsInArray = true ;
}
}
}
CacheProxyData ( ProxyProperty ) ;
TSharedRef < SWidget > ValueWidget = CreateValueWidget ( ParentArrayProperty , StructPropertyHandle , bIsInArray ) ;
2021-10-25 20:05:28 -04:00
FDetailWidgetRow & ValueRow = ChildBuilder . AddCustomRow ( MemberCustomizationPrivate : : DefaultPropertyText ) ;
2021-03-19 15:10:57 -04:00
if ( bIsInArray )
{
ValueRow . NameContent ( )
[
StructPropertyHandle - > CreatePropertyNameWidget ( )
] ;
}
else
{
ValueRow . NameContent ( )
[
2021-03-23 17:55:31 -04:00
CreateNameWidget ( StructPropertyHandle )
2021-03-19 15:10:57 -04:00
] ;
}
TArray < UObject * > OuterObjects ;
StructPropertyHandle - > GetOuterObjects ( OuterObjects ) ;
TArray < TWeakObjectPtr < UMetasoundEditorGraphInput > > Inputs ;
for ( UObject * Object : OuterObjects )
{
if ( UMetasoundEditorGraphInput * Input = Cast < UMetasoundEditorGraphInput > ( Object ) )
{
Inputs . Add ( Input ) ;
}
}
2021-10-12 21:21:22 -04:00
FSimpleDelegate UpdateDocumentInput = FSimpleDelegate : : CreateLambda ( [ InInputs = Inputs ] ( )
2021-03-19 15:10:57 -04:00
{
for ( const TWeakObjectPtr < UMetasoundEditorGraphInput > & GraphInput : InInputs )
{
if ( GraphInput . IsValid ( ) )
{
2021-11-18 16:49:57 -05:00
if ( UMetasoundEditorGraphInputLiteral * InputLiteral = GraphInput - > Literal )
{
InputLiteral - > UpdateDocumentInputLiteral ( ) ;
}
2021-03-19 15:10:57 -04:00
}
}
} ) ;
2021-10-12 21:21:22 -04:00
StructPropertyHandle - > SetOnChildPropertyValueChanged ( UpdateDocumentInput ) ;
2021-03-19 15:10:57 -04:00
ValueRow . ValueContent ( )
[
ValueWidget
] ;
}
void FMetasoundInputArrayDetailCustomizationBase : : CustomizeHeader ( TSharedRef < IPropertyHandle > StructPropertyHandle , FDetailWidgetRow & HeaderRow , IPropertyTypeCustomizationUtils & StructCustomizationUtils )
{
}
2021-11-07 23:43:01 -05:00
FName FMetasoundDataTypeSelector : : GetDataType ( ) const
{
if ( GraphMember . IsValid ( ) )
{
return GraphMember - > TypeName ;
}
return FName ( ) ;
}
void FMetasoundDataTypeSelector : : OnDataTypeSelected ( FName InSelectedTypeName )
{
FName ArrayDataTypeName = FName ( * InSelectedTypeName . ToString ( ) + MemberCustomizationPrivate : : ArrayIdentifier ) ;
FName NewDataTypeName ;
// Update data type based on "Is Array" checkbox and support for arrays.
// If an array type is not supported, default to the base data type.
IMetasoundEditorModule & EditorModule = FModuleManager : : GetModuleChecked < IMetasoundEditorModule > ( " MetaSoundEditor " ) ;
if ( DataTypeArrayCheckbox - > GetCheckedState ( ) = = ECheckBoxState : : Checked )
{
if ( EditorModule . IsRegisteredDataType ( ArrayDataTypeName ) )
{
NewDataTypeName = ArrayDataTypeName ;
}
else
{
check ( EditorModule . IsRegisteredDataType ( InSelectedTypeName ) ) ;
NewDataTypeName = InSelectedTypeName ;
}
}
else
{
if ( EditorModule . IsRegisteredDataType ( InSelectedTypeName ) )
{
NewDataTypeName = InSelectedTypeName ;
}
else
{
check ( EditorModule . IsRegisteredDataType ( ArrayDataTypeName ) ) ;
NewDataTypeName = ArrayDataTypeName ;
}
}
if ( NewDataTypeName = = GraphMember - > TypeName )
{
return ;
}
// Have to stop playback to avoid attempting to change live edit data on invalid input type.
check ( GEditor ) ;
GEditor - > ResetPreviewAudioComponent ( ) ;
if ( GraphMember . IsValid ( ) )
{
GraphMember - > SetDataType ( NewDataTypeName ) ;
}
// Required to rebuild the literal details customization.
// This is seemingly dangerous (as the Builder's raw ptr is cached),
// but the builder cannot be accessed any other way and instances of
// this type are always built from and managed by the parent DetailLayoutBuilder.
check ( DetailLayoutBuilder ) ;
DetailLayoutBuilder - > ForceRefreshDetails ( ) ;
}
2021-10-25 20:05:28 -04:00
void FMetasoundDataTypeSelector : : AddDataTypeSelector ( IDetailLayoutBuilder & InDetailLayout , const FText & InRowName , TWeakObjectPtr < UMetasoundEditorGraphMember > InGraphMember , bool bIsEnabled )
2021-03-19 15:10:57 -04:00
{
2021-11-07 23:43:01 -05:00
if ( ! InGraphMember . IsValid ( ) )
{
return ;
}
2021-03-19 15:10:57 -04:00
DetailLayoutBuilder = & InDetailLayout ;
2021-11-07 23:43:01 -05:00
GraphMember = InGraphMember ;
2021-03-19 15:10:57 -04:00
2021-11-07 23:43:01 -05:00
FString CurrentTypeName = GraphMember - > TypeName . ToString ( ) ;
2021-03-19 15:10:57 -04:00
2021-10-25 20:05:28 -04:00
bool bCurrentTypeIsArray = CurrentTypeName . EndsWith ( MemberCustomizationPrivate : : ArrayIdentifier ) ;
2021-03-19 15:10:57 -04:00
if ( bCurrentTypeIsArray )
{
2021-10-25 20:05:28 -04:00
CurrentTypeName . LeftChopInline ( MemberCustomizationPrivate : : ArrayIdentifier . Len ( ) ) ;
2021-03-19 15:10:57 -04:00
}
2021-04-02 03:03:27 -04:00
IMetasoundEditorModule & EditorModule = FModuleManager : : GetModuleChecked < IMetasoundEditorModule > ( " MetaSoundEditor " ) ;
2021-04-06 21:02:21 -04:00
// Not all types have an equivalent array type. Base types without array
// types should have the "Is Array" checkbox disabled.
2021-10-25 20:05:28 -04:00
const FName ArrayType = * ( CurrentTypeName + MemberCustomizationPrivate : : ArrayIdentifier ) ;
2021-04-08 14:10:56 -04:00
const bool bIsArrayTypeRegistered = EditorModule . IsRegisteredDataType ( ArrayType ) ;
2021-10-25 20:05:28 -04:00
const bool bIsArrayTypeRegisteredHidden = MemberCustomizationPrivate : : HiddenInputTypeNames . Contains ( ArrayType ) ;
2021-04-06 21:02:21 -04:00
2021-12-02 14:23:45 -05:00
TArray < FName > BaseDataTypes ;
2021-03-19 15:10:57 -04:00
EditorModule . IterateDataTypes ( [ & ] ( const FEditorDataType & EditorDataType )
{
2021-11-07 23:43:01 -05:00
const FName & TypeName = EditorDataType . RegistryInfo . DataTypeName ;
2021-04-06 21:02:21 -04:00
2021-12-02 14:23:45 -05:00
// Hide the type from the combo selector if any of the following is true;
const bool bIsArrayType = EditorDataType . RegistryInfo . IsArrayType ( ) ;
const bool bIsVariable = EditorDataType . RegistryInfo . bIsVariable ;
const bool bIsHiddenType = MemberCustomizationPrivate : : HiddenInputTypeNames . Contains ( TypeName ) ;
const bool bHideBaseType = bIsArrayType | | bIsVariable | | bIsHiddenType ;
if ( ! bHideBaseType )
2021-03-19 15:10:57 -04:00
{
2021-12-02 14:23:45 -05:00
BaseDataTypes . Add ( TypeName ) ;
2021-04-07 22:22:52 -04:00
}
2021-03-19 15:10:57 -04:00
} ) ;
2021-12-02 14:23:45 -05:00
BaseDataTypes . Sort ( [ ] ( const FName & DataTypeNameL , const FName & DataTypeNameR )
2021-03-19 15:10:57 -04:00
{
2021-11-07 23:43:01 -05:00
return DataTypeNameL . LexicalLess ( DataTypeNameR ) ;
2021-03-19 15:10:57 -04:00
} ) ;
2021-12-02 14:23:45 -05:00
Algo : : Transform ( BaseDataTypes , ComboOptions , [ ] ( const FName & Name ) { return MakeShared < FString > ( Name . ToString ( ) ) ; } ) ;
2021-11-07 23:43:01 -05:00
2021-12-02 14:23:45 -05:00
InDetailLayout . EditCategory ( " General " ) . AddCustomRow ( InRowName )
2021-07-27 15:36:03 -04:00
. IsEnabled ( bIsEnabled )
2021-03-19 15:10:57 -04:00
. NameContent ( )
[
SNew ( STextBlock )
. Text ( InRowName )
. Font ( IDetailLayoutBuilder : : GetDetailFont ( ) )
]
. ValueContent ( )
[
SNew ( SHorizontalBox )
+ SHorizontalBox : : Slot ( )
2021-11-07 23:43:01 -05:00
. AutoWidth ( )
. HAlign ( HAlign_Left )
2021-03-19 15:10:57 -04:00
. VAlign ( VAlign_Center )
2021-11-07 23:43:01 -05:00
. Padding ( 1.0f , 0.0f , 0.0f , 0.0f )
2021-03-19 15:10:57 -04:00
[
2021-11-07 23:43:01 -05:00
SAssignNew ( DataTypeComboBox , SSearchableComboBox )
. OptionsSource ( & ComboOptions )
. OnGenerateWidget_Lambda ( [ ] ( TSharedPtr < FString > InItem )
2021-03-19 15:10:57 -04:00
{
2021-11-07 23:43:01 -05:00
return SNew ( STextBlock )
. Text ( FText : : FromString ( * InItem ) ) ;
2021-03-19 15:10:57 -04:00
} )
2021-11-07 23:43:01 -05:00
. OnSelectionChanged_Lambda ( [ this ] ( TSharedPtr < FString > InNewName , ESelectInfo : : Type InSelectInfo )
{
if ( InSelectInfo ! = ESelectInfo : : OnNavigation )
{
OnDataTypeSelected ( FName ( * InNewName ) ) ;
}
} )
. Content ( )
[
SNew ( STextBlock )
. Text_Lambda ( [ this ] ( )
{
return FText : : FromName ( GetDataType ( ) ) ;
} )
]
2021-03-19 15:10:57 -04:00
]
+ SHorizontalBox : : Slot ( )
2021-11-07 23:43:01 -05:00
. AutoWidth ( )
. HAlign ( HAlign_Right )
2021-03-19 15:10:57 -04:00
. VAlign ( VAlign_Center )
2021-11-07 23:43:01 -05:00
. Padding ( 2.0f , 0.0f , 0.0f , 0.0f )
2021-03-19 15:10:57 -04:00
[
SAssignNew ( DataTypeArrayCheckbox , SCheckBox )
2021-04-08 14:10:56 -04:00
. IsEnabled ( bIsArrayTypeRegistered & & ! bIsArrayTypeRegisteredHidden )
2021-10-25 20:05:28 -04:00
. IsChecked_Lambda ( [ this , InGraphMember ] ( )
2021-03-19 15:10:57 -04:00
{
2021-10-25 20:05:28 -04:00
return OnGetDataTypeArrayCheckState ( InGraphMember ) ;
2021-03-19 15:10:57 -04:00
} )
2021-10-25 20:05:28 -04:00
. OnCheckStateChanged_Lambda ( [ this , InGraphMember ] ( ECheckBoxState InNewState )
2021-03-19 15:10:57 -04:00
{
2021-10-25 20:05:28 -04:00
OnDataTypeArrayChanged ( InGraphMember , InNewState ) ;
2021-03-19 15:10:57 -04:00
} )
[
SNew ( STextBlock )
. Text ( LOCTEXT ( " Node_IsArray " , " Is Array " ) )
. Font ( IDetailLayoutBuilder : : GetDetailFont ( ) )
]
]
] ;
2021-11-07 23:43:01 -05:00
auto NameMatchesPredicate = [ CurrentTypeName ] ( const TSharedPtr < FString > & Item ) { return * Item = = CurrentTypeName ; } ;
const TSharedPtr < FString > * SelectedItem = ComboOptions . FindByPredicate ( NameMatchesPredicate ) ;
if ( ensure ( SelectedItem ) )
{
DataTypeComboBox - > SetSelectedItem ( * SelectedItem ) ;
}
2021-03-19 15:10:57 -04:00
}
2021-10-25 20:05:28 -04:00
ECheckBoxState FMetasoundDataTypeSelector : : OnGetDataTypeArrayCheckState ( TWeakObjectPtr < UMetasoundEditorGraphMember > InGraphMember ) const
2021-03-19 15:10:57 -04:00
{
2021-10-25 20:05:28 -04:00
if ( InGraphMember . IsValid ( ) )
2021-03-19 15:10:57 -04:00
{
2021-10-25 20:05:28 -04:00
FString CurrentTypeName = InGraphMember - > TypeName . ToString ( ) ;
bool bCurrentTypeIsArray = CurrentTypeName . EndsWith ( MemberCustomizationPrivate : : ArrayIdentifier ) ;
2021-03-19 15:10:57 -04:00
return bCurrentTypeIsArray ? ECheckBoxState : : Checked : ECheckBoxState : : Unchecked ;
}
return ECheckBoxState : : Undetermined ;
}
void FMetasoundInputDetailCustomization : : CustomizeDetails ( IDetailLayoutBuilder & DetailLayout )
{
using namespace Frontend ;
2021-10-25 20:05:28 -04:00
TMetasoundGraphMemberDetailCustomization < UMetasoundEditorGraphInput > : : CustomizeDetails ( DetailLayout ) ;
2021-03-19 15:10:57 -04:00
2021-10-25 20:05:28 -04:00
if ( ! GraphMember . IsValid ( ) )
2021-03-19 15:10:57 -04:00
{
return ;
}
IDetailCategoryBuilder & CategoryBuilder = DetailLayout . EditCategory ( " General " ) ;
2021-11-22 15:55:50 -05:00
const bool bIsInterfaceMember = CastChecked < UMetasoundEditorGraphVertex > ( GraphMember ) - > IsInterfaceMember ( ) ;
2021-07-27 15:36:03 -04:00
const bool bIsGraphEditable = IsGraphEditable ( ) ;
2021-09-13 14:14:37 -04:00
NameEditableTextBox = SNew ( SEditableTextBox )
. Text ( this , & FMetasoundInputDetailCustomization : : GetName )
. OnTextChanged ( this , & FMetasoundInputDetailCustomization : : OnNameChanged )
. OnTextCommitted ( this , & FMetasoundInputDetailCustomization : : OnNameCommitted )
2021-11-22 15:55:50 -05:00
. IsReadOnly ( bIsInterfaceMember | | ! bIsGraphEditable )
2021-09-13 14:14:37 -04:00
. Font ( IDetailLayoutBuilder : : GetDetailFont ( ) ) ;
2021-03-19 15:10:57 -04:00
DisplayNameEditableTextBox = SNew ( SEditableTextBox )
. Text ( this , & FMetasoundInputDetailCustomization : : GetDisplayName )
. OnTextCommitted ( this , & FMetasoundInputDetailCustomization : : OnDisplayNameCommitted )
2021-11-22 15:55:50 -05:00
. IsReadOnly ( bIsInterfaceMember | | ! bIsGraphEditable )
2021-03-19 15:10:57 -04:00
. Font ( IDetailLayoutBuilder : : GetDetailFont ( ) ) ;
2021-10-25 20:05:28 -04:00
CategoryBuilder . AddCustomRow ( MemberCustomizationPrivate : : InputNameText )
2021-11-22 15:55:50 -05:00
. EditCondition ( ! bIsInterfaceMember & & bIsGraphEditable , nullptr )
2021-03-19 15:10:57 -04:00
. NameContent ( )
[
SNew ( STextBlock )
. Font ( IDetailLayoutBuilder : : GetDetailFontBold ( ) )
2021-10-25 20:05:28 -04:00
. Text ( MemberCustomizationPrivate : : InputNameText )
2021-09-13 14:14:37 -04:00
. ToolTipText ( LOCTEXT ( " InputName_Description " , " Name used by external systems to identify input. Used as DisplayName within MetaSound Graph Editor if no DisplayName is provided. " ) )
2021-03-19 15:10:57 -04:00
]
. ValueContent ( )
[
2021-09-13 14:14:37 -04:00
NameEditableTextBox . ToSharedRef ( )
2021-03-19 15:10:57 -04:00
] ;
2021-09-13 14:14:37 -04:00
// TODO: Enable and use proper FText property editor
2021-10-25 20:05:28 -04:00
// CategoryBuilder.AddCustomRow(MemberCustomizationPrivate::InputDisplayNameText)
2021-11-22 15:55:50 -05:00
// .EditCondition(!bIsInterfaceMember && bIsGraphEditable, nullptr)
2021-09-13 14:14:37 -04:00
// .NameContent()
// [
// SNew(STextBlock)
// .Font(IDetailLayoutBuilder::GetDetailFontBold())
2021-10-25 20:05:28 -04:00
// .Text(MemberCustomizationPrivate::InputDisplayNameText)
2021-09-13 14:14:37 -04:00
// .ToolTipText(LOCTEXT("InputDisplayName_Description", "Optional, localized name used within the MetaSounds editor(s) to describe the given input."))
// ]
// .ValueContent()
// [
// DisplayNameEditableTextBox.ToSharedRef()
// ];
2021-10-25 20:05:28 -04:00
CategoryBuilder . AddCustomRow ( MemberCustomizationPrivate : : NodeTooltipText )
2021-11-22 15:55:50 -05:00
. EditCondition ( ! bIsInterfaceMember & & bIsGraphEditable , nullptr )
2021-03-19 15:10:57 -04:00
. NameContent ( )
[
SNew ( STextBlock )
. Font ( IDetailLayoutBuilder : : GetDetailFontBold ( ) )
2021-10-25 20:05:28 -04:00
. Text ( MemberCustomizationPrivate : : NodeTooltipText )
2021-03-19 15:10:57 -04:00
]
. ValueContent ( )
[
SNew ( SMultiLineEditableTextBox )
. Text ( this , & FMetasoundInputDetailCustomization : : GetTooltip )
. OnTextCommitted ( this , & FMetasoundInputDetailCustomization : : OnTooltipCommitted )
2021-11-22 15:55:50 -05:00
. IsReadOnly ( bIsInterfaceMember | | ! bIsGraphEditable )
2021-03-19 15:10:57 -04:00
. ModiferKeyForNewLine ( EModifierKey : : Shift )
. RevertTextOnEscape ( true )
2021-10-25 20:05:28 -04:00
. WrapTextAt ( MemberCustomizationPrivate : : DetailsTitleMaxWidth - MemberCustomizationPrivate : : DetailsTitleWrapPadding )
2021-03-19 15:10:57 -04:00
. Font ( IDetailLayoutBuilder : : GetDetailFont ( ) )
] ;
2021-11-22 15:55:50 -05:00
DataTypeSelector - > AddDataTypeSelector ( DetailLayout , MemberCustomizationPrivate : : DataTypeNameText , GraphMember , ! bIsInterfaceMember & & bIsGraphEditable ) ;
2021-03-19 15:10:57 -04:00
IDetailCategoryBuilder & DefaultCategoryBuilder = DetailLayout . EditCategory ( " DefaultValue " ) ;
TSharedPtr < IPropertyHandle > LiteralHandle = DetailLayout . GetProperty ( GET_MEMBER_NAME_CHECKED ( UMetasoundEditorGraphInput , Literal ) ) ;
2021-10-25 20:05:28 -04:00
if ( ensure ( GraphMember . IsValid ( ) ) & & ensure ( LiteralHandle . IsValid ( ) ) )
2021-03-19 15:10:57 -04:00
{
UObject * LiteralObject = nullptr ;
if ( LiteralHandle - > GetValue ( LiteralObject ) = = FPropertyAccess : : Success )
{
if ( ensure ( LiteralObject ) )
{
LiteralHandle - > MarkHiddenByCustomization ( ) ;
2021-10-12 21:21:22 -04:00
TSharedPtr < IPropertyHandle > DefaultValueHandle ;
2021-03-19 15:10:57 -04:00
if ( IDetailPropertyRow * Row = DefaultCategoryBuilder . AddExternalObjectProperty ( TArray < UObject * > ( { LiteralObject } ) , " Default " ) )
{
DefaultValueHandle = Row - > GetPropertyHandle ( ) ;
if ( DefaultValueHandle . IsValid ( ) )
{
SetDefaultPropertyMetaData ( DefaultValueHandle . ToSharedRef ( ) ) ;
2021-10-25 20:05:28 -04:00
FSimpleDelegate UpdateDocumentInput = FSimpleDelegate : : CreateLambda ( [ GraphMember = this - > GraphMember ] ( )
2021-03-19 15:10:57 -04:00
{
2021-10-25 20:05:28 -04:00
if ( GraphMember . IsValid ( ) )
2021-03-19 15:10:57 -04:00
{
2021-11-18 16:49:57 -05:00
if ( UMetasoundEditorGraphInputLiteral * InputLiteral = GraphMember - > Literal )
{
InputLiteral - > UpdateDocumentInputLiteral ( ) ;
}
2021-03-19 15:10:57 -04:00
}
} ) ;
2021-10-12 21:21:22 -04:00
DefaultValueHandle - > SetOnPropertyValueChanged ( UpdateDocumentInput ) ;
DefaultValueHandle - > SetOnChildPropertyValueChanged ( UpdateDocumentInput ) ;
2021-03-19 15:10:57 -04:00
TSharedPtr < IPropertyHandleArray > DefaultValueArray = DefaultValueHandle - > AsArray ( ) ;
if ( DefaultValueArray . IsValid ( ) )
{
2021-10-12 21:21:22 -04:00
DefaultValueArray - > SetOnNumElementsChanged ( UpdateDocumentInput ) ;
2021-03-19 15:10:57 -04:00
}
}
}
2021-10-12 21:21:22 -04:00
IMetasoundEditorModule & EditorModule = FModuleManager : : GetModuleChecked < IMetasoundEditorModule > ( " MetaSoundEditor " ) ;
LiteralCustomization = EditorModule . CreateInputLiteralCustomization ( * LiteralObject - > GetClass ( ) , DefaultCategoryBuilder ) ;
if ( LiteralCustomization . IsValid ( ) )
{
LiteralCustomization - > CustomizeLiteral ( * CastChecked < UMetasoundEditorGraphInputLiteral > ( LiteralObject ) , DefaultValueHandle ) ;
}
2021-11-07 23:43:01 -05:00
UMetasoundEditorGraphInputFloat * InputFloat = Cast < UMetasoundEditorGraphInputFloat > ( LiteralObject ) ;
if ( InputFloat )
{
// add input widget properties
IDetailCategoryBuilder & WidgetCategoryBuilder = DetailLayout . EditCategory ( " Widget " ) ;
WidgetCategoryBuilder . AddExternalObjectProperty ( TArray < UObject * > ( { InputFloat } ) , GET_MEMBER_NAME_CHECKED ( UMetasoundEditorGraphInputFloat , InputWidgetType ) ) ;
WidgetCategoryBuilder . AddExternalObjectProperty ( TArray < UObject * > ( { InputFloat } ) , GET_MEMBER_NAME_CHECKED ( UMetasoundEditorGraphInputFloat , InputWidgetOrientation ) ) ;
WidgetCategoryBuilder . AddExternalObjectProperty ( TArray < UObject * > ( { InputFloat } ) , GET_MEMBER_NAME_CHECKED ( UMetasoundEditorGraphInputFloat , InputWidgetValueType ) ) ;
}
2021-03-19 15:10:57 -04:00
}
else
{
DefaultCategoryBuilder . AddProperty ( LiteralHandle ) ;
}
}
}
}
2021-10-25 20:05:28 -04:00
void FMetasoundDataTypeSelector : : OnDataTypeArrayChanged ( TWeakObjectPtr < UMetasoundEditorGraphMember > InGraphMember , ECheckBoxState InNewState )
2021-03-19 15:10:57 -04:00
{
2021-11-07 23:43:01 -05:00
if ( InGraphMember . IsValid ( ) & & DataTypeComboBox . IsValid ( ) )
2021-03-19 15:10:57 -04:00
{
TSharedPtr < FString > DataTypeRoot = DataTypeComboBox - > GetSelectedItem ( ) ;
if ( ensure ( DataTypeRoot . IsValid ( ) ) )
{
FString DataTypeString = * DataTypeRoot . Get ( ) ;
if ( InNewState = = ECheckBoxState : : Checked )
{
2021-10-25 20:05:28 -04:00
DataTypeString + = MemberCustomizationPrivate : : ArrayIdentifier ;
2021-03-19 15:10:57 -04:00
}
2021-03-24 16:42:25 -04:00
// Have to stop playback to avoid attempting to change live edit data on invalid input type.
check ( GEditor ) ;
GEditor - > ResetPreviewAudioComponent ( ) ;
2021-10-25 20:05:28 -04:00
InGraphMember - > SetDataType ( FName ( DataTypeString ) ) ;
2021-03-19 15:10:57 -04:00
// Required to rebuild the literal details customization.
// This is seemingly dangerous (as the Builder's raw ptr is cached),
// but the builder cannot be accessed any other way and instances of
// this type are always built from and managed by the parent DetailLayoutBuilder.
check ( DetailLayoutBuilder ) ;
DetailLayoutBuilder - > ForceRefreshDetails ( ) ;
}
}
}
void FMetasoundInputDetailCustomization : : SetDefaultPropertyMetaData ( TSharedRef < IPropertyHandle > InDefaultPropertyHandle ) const
{
using namespace Frontend ;
2021-10-25 20:05:28 -04:00
if ( ! GraphMember . IsValid ( ) )
2021-03-19 15:10:57 -04:00
{
return ;
}
FMetasoundFrontendRegistryContainer * Registry = FMetasoundFrontendRegistryContainer : : Get ( ) ;
if ( ! ensure ( Registry ) )
{
return ;
}
const FName TypeName = GetLiteralDataType ( ) ;
if ( TypeName . IsNone ( ) )
{
return ;
}
FString TypeNameString = TypeName . ToString ( ) ;
2021-10-25 20:05:28 -04:00
if ( TypeNameString . EndsWith ( MemberCustomizationPrivate : : ArrayIdentifier ) )
2021-03-19 15:10:57 -04:00
{
2021-10-25 20:05:28 -04:00
TypeNameString = TypeNameString . LeftChop ( MemberCustomizationPrivate : : ArrayIdentifier . Len ( ) ) ;
2021-03-19 15:10:57 -04:00
}
2021-10-25 20:05:28 -04:00
InDefaultPropertyHandle - > SetInstanceMetaData ( MemberCustomizationPrivate : : DataTypeNameIdentifier , TypeNameString ) ;
2021-03-19 15:10:57 -04:00
FDataTypeRegistryInfo DataTypeInfo ;
2021-08-19 09:59:27 -04:00
if ( ! ensure ( IDataTypeRegistry : : Get ( ) . GetDataTypeInfo ( TypeName , DataTypeInfo ) ) )
2021-03-19 15:10:57 -04:00
{
return ;
}
const EMetasoundFrontendLiteralType LiteralType = GetMetasoundFrontendLiteralType ( DataTypeInfo . PreferredLiteralType ) ;
if ( LiteralType ! = EMetasoundFrontendLiteralType : : UObject & & LiteralType ! = EMetasoundFrontendLiteralType : : UObjectArray )
{
return ;
}
UClass * ProxyGenClass = DataTypeInfo . ProxyGeneratorClass ;
if ( ProxyGenClass )
{
const FString ClassName = ProxyGenClass - > GetName ( ) ;
2021-10-25 20:05:28 -04:00
InDefaultPropertyHandle - > SetInstanceMetaData ( MemberCustomizationPrivate : : ProxyGeneratorClassNameIdentifier , ClassName ) ;
2021-03-19 15:10:57 -04:00
}
}
FName FMetasoundInputDetailCustomization : : GetLiteralDataType ( ) const
{
2021-10-25 20:05:28 -04:00
return GraphMember - > TypeName ;
2021-03-19 15:10:57 -04:00
}
void FMetasoundOutputDetailCustomization : : CustomizeDetails ( IDetailLayoutBuilder & DetailLayout )
{
using namespace Frontend ;
2021-10-25 20:05:28 -04:00
TMetasoundGraphMemberDetailCustomization < UMetasoundEditorGraphOutput > : : CustomizeDetails ( DetailLayout ) ;
if ( ! GraphMember . IsValid ( ) )
2021-03-19 15:10:57 -04:00
{
return ;
}
IDetailCategoryBuilder & CategoryBuilder = DetailLayout . EditCategory ( " General " ) ;
2021-11-22 15:55:50 -05:00
const bool bIsInterfaceMember = CastChecked < UMetasoundEditorGraphVertex > ( GraphMember ) - > IsInterfaceMember ( ) ;
2021-07-27 15:36:03 -04:00
const bool bIsGraphEditable = IsGraphEditable ( ) ;
2021-09-13 14:14:37 -04:00
NameEditableTextBox = SNew ( SEditableTextBox )
. Text ( this , & FMetasoundOutputDetailCustomization : : GetName )
. OnTextChanged ( this , & FMetasoundOutputDetailCustomization : : OnNameChanged )
. OnTextCommitted ( this , & FMetasoundOutputDetailCustomization : : OnNameCommitted )
2021-11-22 15:55:50 -05:00
. IsReadOnly ( bIsInterfaceMember | | ! bIsGraphEditable )
2021-09-13 14:14:37 -04:00
. Font ( IDetailLayoutBuilder : : GetDetailFont ( ) ) ;
2021-03-19 15:10:57 -04:00
DisplayNameEditableTextBox = SNew ( SEditableTextBox )
. Text ( this , & FMetasoundOutputDetailCustomization : : GetDisplayName )
. OnTextCommitted ( this , & FMetasoundOutputDetailCustomization : : OnDisplayNameCommitted )
2021-11-22 15:55:50 -05:00
. IsReadOnly ( bIsInterfaceMember | | ! bIsGraphEditable )
2021-03-19 15:10:57 -04:00
. Font ( IDetailLayoutBuilder : : GetDetailFont ( ) ) ;
2021-10-25 20:05:28 -04:00
CategoryBuilder . AddCustomRow ( MemberCustomizationPrivate : : OutputNameText )
2021-11-22 15:55:50 -05:00
. EditCondition ( ! bIsInterfaceMember & & bIsGraphEditable , nullptr )
2021-03-19 15:10:57 -04:00
. NameContent ( )
[
SNew ( STextBlock )
. Font ( IDetailLayoutBuilder : : GetDetailFontBold ( ) )
2021-10-25 20:05:28 -04:00
. Text ( MemberCustomizationPrivate : : OutputNameText )
2021-09-13 14:14:37 -04:00
. ToolTipText ( LOCTEXT ( " OutputName_Description " , " Name used by external systems to identify output. Used as DisplayName within MetaSound Graph Editor if no DisplayName is provided. " ) )
2021-03-19 15:10:57 -04:00
]
. ValueContent ( )
[
2021-09-13 14:14:37 -04:00
NameEditableTextBox . ToSharedRef ( )
2021-03-19 15:10:57 -04:00
] ;
2021-09-13 14:14:37 -04:00
// TODO: Enable and use proper FText property editor
2021-10-25 20:05:28 -04:00
// CategoryBuilder.AddCustomRow(MemberCustomizationPrivate::OutputDisplayNameText)
2021-11-22 15:55:50 -05:00
// .EditCondition(!bIsInterfaceMember && bIsGraphEditable, nullptr)
2021-09-13 14:14:37 -04:00
// .NameContent()
// [
// SNew(STextBlock)
// .Font(IDetailLayoutBuilder::GetDetailFontBold())
2021-10-25 20:05:28 -04:00
// .Text(MemberCustomizationPrivate::OutputDisplayNameText)
2021-09-13 14:14:37 -04:00
// .ToolTipText(LOCTEXT("OutputDisplayName_Description", "Optional, localized name used within the MetaSounds editor(s) to describe the given output."))
// ]
// .ValueContent()
// [
// DisplayNameEditableTextBox.ToSharedRef()
// ];
2021-10-25 20:05:28 -04:00
CategoryBuilder . AddCustomRow ( MemberCustomizationPrivate : : NodeTooltipText )
2021-11-22 15:55:50 -05:00
. EditCondition ( ! bIsInterfaceMember & & bIsGraphEditable , nullptr )
2021-03-19 15:10:57 -04:00
. NameContent ( )
[
SNew ( STextBlock )
. Font ( IDetailLayoutBuilder : : GetDetailFontBold ( ) )
2021-10-25 20:05:28 -04:00
. Text ( MemberCustomizationPrivate : : NodeTooltipText )
2021-03-19 15:10:57 -04:00
]
. ValueContent ( )
[
SNew ( SMultiLineEditableTextBox )
. Text ( this , & FMetasoundOutputDetailCustomization : : GetTooltip )
. OnTextCommitted ( this , & FMetasoundOutputDetailCustomization : : OnTooltipCommitted )
2021-11-22 15:55:50 -05:00
. IsReadOnly ( bIsInterfaceMember | | ! bIsGraphEditable )
2021-03-19 15:10:57 -04:00
. ModiferKeyForNewLine ( EModifierKey : : Shift )
. RevertTextOnEscape ( true )
2021-10-25 20:05:28 -04:00
. WrapTextAt ( MemberCustomizationPrivate : : DetailsTitleMaxWidth - MemberCustomizationPrivate : : DetailsTitleWrapPadding )
2021-03-19 15:10:57 -04:00
. Font ( IDetailLayoutBuilder : : GetDetailFont ( ) )
] ;
2021-11-22 15:55:50 -05:00
DataTypeSelector - > AddDataTypeSelector ( DetailLayout , MemberCustomizationPrivate : : DataTypeNameText , GraphMember , ! bIsInterfaceMember & & bIsGraphEditable ) ;
2021-03-19 15:10:57 -04:00
}
void FMetasoundOutputDetailCustomization : : SetDefaultPropertyMetaData ( TSharedRef < IPropertyHandle > InDefaultPropertyHandle ) const
{
using namespace Frontend ;
2021-10-25 20:05:28 -04:00
if ( ! GraphMember . IsValid ( ) )
2021-03-19 15:10:57 -04:00
{
return ;
}
FMetasoundFrontendRegistryContainer * Registry = FMetasoundFrontendRegistryContainer : : Get ( ) ;
if ( ! ensure ( Registry ) )
{
return ;
}
const FName TypeName = GetLiteralDataType ( ) ;
if ( TypeName . IsNone ( ) )
{
return ;
}
FString TypeNameString = TypeName . ToString ( ) ;
2021-10-25 20:05:28 -04:00
if ( TypeNameString . EndsWith ( MemberCustomizationPrivate : : ArrayIdentifier ) )
2021-03-19 15:10:57 -04:00
{
2021-10-25 20:05:28 -04:00
TypeNameString = TypeNameString . LeftChop ( MemberCustomizationPrivate : : ArrayIdentifier . Len ( ) ) ;
2021-03-19 15:10:57 -04:00
}
2021-10-25 20:05:28 -04:00
InDefaultPropertyHandle - > SetInstanceMetaData ( MemberCustomizationPrivate : : DataTypeNameIdentifier , TypeNameString ) ;
2021-03-19 15:10:57 -04:00
FDataTypeRegistryInfo DataTypeInfo ;
2021-08-19 09:59:27 -04:00
if ( ! ensure ( IDataTypeRegistry : : Get ( ) . GetDataTypeInfo ( TypeName , DataTypeInfo ) ) )
2021-03-19 15:10:57 -04:00
{
return ;
}
const EMetasoundFrontendLiteralType LiteralType = GetMetasoundFrontendLiteralType ( DataTypeInfo . PreferredLiteralType ) ;
if ( LiteralType ! = EMetasoundFrontendLiteralType : : UObject & & LiteralType ! = EMetasoundFrontendLiteralType : : UObjectArray )
{
return ;
}
UClass * ProxyGenClass = DataTypeInfo . ProxyGeneratorClass ;
if ( ProxyGenClass )
{
const FString ClassName = ProxyGenClass - > GetName ( ) ;
2021-10-25 20:05:28 -04:00
InDefaultPropertyHandle - > SetInstanceMetaData ( MemberCustomizationPrivate : : ProxyGeneratorClassNameIdentifier , ClassName ) ;
2021-03-19 15:10:57 -04:00
}
}
FName FMetasoundOutputDetailCustomization : : GetLiteralDataType ( ) const
{
2021-10-25 20:05:28 -04:00
return GraphMember - > TypeName ;
2021-03-19 15:10:57 -04:00
}
} // namespace Editor
} // namespace Metasound
# undef LOCTEXT_NAMESPACE