2021-03-19 15:10:57 -04:00
// Copyright Epic Games, Inc. All Rights Reserved.
# include "MetasoundNodeDetailCustomization.h"
2022-10-10 15:21:30 -04:00
# include "Analysis/MetasoundFrontendAnalyzerAddress.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 "Delegates/Delegate.h"
# include "Framework/Notifications/NotificationManager.h"
2024-02-01 19:54:42 -05:00
# include "HAL/PlatformApplicationMisc.h"
2021-03-19 15:10:57 -04:00
# include "IDetailChildrenBuilder.h"
# include "IDetailGroup.h"
# include "Internationalization/Text.h"
2021-04-07 02:59:10 -04:00
# include "MetasoundDataReference.h"
2021-12-13 18:15:01 -05:00
# include "MetasoundDataReferenceMacro.h"
2022-07-18 17:14:25 -04:00
# include "MetasoundEditorGraphBuilder.h"
2021-12-13 18:15:01 -05:00
# include "MetasoundEditorGraphInputNode.h"
2021-11-07 23:43:01 -05:00
# include "MetasoundEditorGraphSchema.h"
2021-03-19 15:10:57 -04:00
# include "MetasoundFrontend.h"
# include "MetasoundFrontendController.h"
2021-12-13 18:15:01 -05:00
# include "MetasoundFrontendDataTypeRegistry.h"
2021-03-19 15:10:57 -04:00
# include "MetasoundFrontendRegistries.h"
2022-03-22 14:01:46 -04:00
# include "Modules/ModuleManager.h"
2021-03-19 15:10:57 -04:00
# include "PropertyCustomizationHelpers.h"
# include "PropertyEditorDelegates.h"
2022-01-04 15:17:54 -05:00
# include "SAssetDropTarget.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"
2022-10-19 06:39:08 -04:00
# include "Styling/SlateColor.h"
2021-03-19 15:10:57 -04:00
# include "Templates/Casts.h"
# include "Templates/SharedPointer.h"
2022-03-22 14:01:46 -04:00
# include "Templates/UniquePtr.h"
2021-03-19 15:10:57 -04:00
# 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/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
{
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 " ,
2022-10-10 15:21:30 -04:00
" Audio:Stereo " ,
2022-12-15 17:03:02 -05:00
GetMetasoundDataTypeName < Frontend : : FAnalyzerAddress > ( ) ,
" MetasoundParameterPack "
2021-04-06 21:02:21 -04:00
} ;
2022-01-04 15:17:54 -05:00
2022-02-09 12:52:07 -05:00
static const FText OverrideInputDefaultText = LOCTEXT ( " OverridePresetInputDefault " , " Override Inherited Default " ) ;
static const FText OverrideInputDefaultTooltip = LOCTEXT ( " OverridePresetInputTooltip " ,
2022-04-25 13:29:29 -04:00
" Enables overriding the input's inherited default value otherwise provided by the referenced graph. Setting to true disables auto-updating the input's default value if modified on the referenced asset. " ) ;
static const FText ConstructorPinText = LOCTEXT ( " ConstructorPinText " , " Is Constructor Pin " ) ;
static const FText ConstructorPinTooltip = LOCTEXT ( " ConstructorPinTooltip " ,
2022-08-23 18:22:57 -04:00
" Whether this input or output is a constructor pin. Constructor values are only read on construction (on play), and are not dynamically updated at runtime. " ) ;
2022-02-09 12:52:07 -05:00
2022-01-04 15:17:54 -05:00
void GetDataTypeFromElementPropertyHandle ( TSharedPtr < IPropertyHandle > ElementPropertyHandle , Frontend : : FDataTypeRegistryInfo & OutDataTypeInfo )
{
using namespace Frontend ;
TArray < UObject * > OuterObjects ;
ElementPropertyHandle - > GetOuterObjects ( OuterObjects ) ;
if ( OuterObjects . Num ( ) = = 1 )
{
UObject * Outer = OuterObjects . Last ( ) ;
if ( const UMetasoundEditorGraphMemberDefaultLiteral * DefaultLiteral = Cast < UMetasoundEditorGraphMemberDefaultLiteral > ( Outer ) )
{
if ( const UMetasoundEditorGraphMember * Member = Cast < UMetasoundEditorGraphMember > ( DefaultLiteral - > GetOuter ( ) ) )
{
2022-07-14 17:51:07 -04:00
FName DataTypeName = Member - > GetDataType ( ) ;
ensure ( IDataTypeRegistry : : Get ( ) . GetDataTypeInfo ( DataTypeName , OutDataTypeInfo ) ) ;
if ( OutDataTypeInfo . bIsArrayType )
{
DataTypeName = CreateElementTypeNameFromArrayTypeName ( DataTypeName ) ;
const bool bIsHiddenType = HiddenInputTypeNames . Contains ( DataTypeName ) ;
OutDataTypeInfo = { } ;
if ( ! bIsHiddenType )
{
ensure ( IDataTypeRegistry : : Get ( ) . GetDataTypeInfo ( DataTypeName , OutDataTypeInfo ) ) ;
}
}
2022-01-04 15:17:54 -05:00
}
}
}
}
// If DataType is an array type, creates & returns the array's
// element type. Otherwise, returns this type's DataTypeName.
FName GetPrimitiveTypeName ( const Frontend : : FDataTypeRegistryInfo & InDataTypeInfo )
{
2022-07-14 17:51:07 -04:00
return InDataTypeInfo . bIsArrayType
2022-01-04 15:17:54 -05:00
? CreateElementTypeNameFromArrayTypeName ( InDataTypeInfo . DataTypeName )
: InDataTypeInfo . DataTypeName ;
}
2021-10-25 20:05:28 -04:00
} // namespace MemberCustomizationPrivate
2021-10-12 21:21:22 -04:00
FMetasoundFloatLiteralCustomization : : ~ FMetasoundFloatLiteralCustomization ( )
{
if ( FloatLiteral . IsValid ( ) )
{
2021-12-13 18:15:01 -05:00
FloatLiteral - > OnClampChanged . Remove ( OnClampChangedDelegateHandle ) ;
2021-10-12 21:21:22 -04:00
}
}
2022-02-09 12:52:07 -05:00
TArray < IDetailPropertyRow * > FMetasoundFloatLiteralCustomization : : CustomizeLiteral ( UMetasoundEditorGraphMemberDefaultLiteral & InLiteral , IDetailLayoutBuilder & InDetailLayout )
2021-10-12 21:21:22 -04:00
{
2022-01-04 15:17:54 -05:00
check ( DefaultCategoryBuilder ) ;
2021-10-12 21:21:22 -04:00
2021-12-13 18:15:01 -05:00
UMetasoundEditorGraphMemberDefaultFloat * DefaultFloat = Cast < UMetasoundEditorGraphMemberDefaultFloat > ( & InLiteral ) ;
if ( ! ensure ( DefaultFloat ) )
2021-10-12 21:21:22 -04:00
{
2022-02-09 12:52:07 -05:00
return { } ;
2021-10-12 21:21:22 -04:00
}
2021-12-13 18:15:01 -05:00
FloatLiteral = DefaultFloat ;
2021-10-12 21:21:22 -04:00
2022-02-09 12:52:07 -05:00
TArray < IDetailPropertyRow * > DefaultRows ;
2022-01-04 15:17:54 -05:00
TSharedPtr < IPropertyHandle > DefaultValueHandle ;
IDetailPropertyRow * Row = DefaultCategoryBuilder - > AddExternalObjectProperty ( TArray < UObject * > ( { DefaultFloat } ) , UMetasoundEditorGraphMemberDefaultFloat : : GetDefaultPropertyName ( ) ) ;
if ( ensure ( Row ) )
{
2022-02-09 12:52:07 -05:00
DefaultRows . Add ( Row ) ;
2022-01-04 15:17:54 -05:00
DefaultValueHandle = Row - > GetPropertyHandle ( ) ;
}
2022-10-19 15:34:44 -04:00
// Apply the clamp range to the default value if not using a widget and ClampDefault is true
2022-01-14 14:01:09 -05:00
const bool bUsingWidget = DefaultFloat - > WidgetType ! = EMetasoundMemberDefaultWidget : : None ;
2022-10-19 15:34:44 -04:00
const bool bShouldClampDefaultValue = bUsingWidget | | ( ! bUsingWidget & & DefaultFloat - > ClampDefault ) ;
2022-01-14 14:01:09 -05:00
2022-02-09 12:52:07 -05:00
IDetailPropertyRow * ClampRow = DefaultCategoryBuilder - > AddExternalObjectProperty ( TArray < UObject * > ( { DefaultFloat } ) , GET_MEMBER_NAME_CHECKED ( UMetasoundEditorGraphMemberDefaultFloat , ClampDefault ) ) ;
if ( ensure ( ClampRow ) )
2021-10-12 21:21:22 -04:00
{
2022-02-09 12:52:07 -05:00
DefaultRows . Add ( ClampRow ) ;
if ( DefaultValueHandle . IsValid ( ) )
2021-10-12 21:21:22 -04:00
{
2022-02-09 12:52:07 -05:00
if ( bShouldClampDefaultValue )
{
FVector2D Range = DefaultFloat - > GetRange ( ) ;
DefaultValueHandle - > SetInstanceMetaData ( " ClampMin " , FString : : Printf ( TEXT ( " %f " ) , Range . X ) ) ;
DefaultValueHandle - > SetInstanceMetaData ( " ClampMax " , FString : : Printf ( TEXT ( " %f " ) , Range . Y ) ) ;
}
else // Stop clamping
{
DefaultValueHandle - > SetInstanceMetaData ( " ClampMin " , " " ) ;
DefaultValueHandle - > SetInstanceMetaData ( " ClampMax " , " " ) ;
}
2021-10-12 21:21:22 -04:00
}
2021-12-13 18:15:01 -05:00
DefaultFloat - > OnClampChanged . Remove ( OnClampChangedDelegateHandle ) ;
OnClampChangedDelegateHandle = DefaultFloat - > OnClampChanged . AddLambda ( [ this ] ( bool ClampInput )
2021-10-12 21:21:22 -04:00
{
if ( FloatLiteral . IsValid ( ) )
{
2021-12-13 18:15:01 -05:00
FloatLiteral - > OnClampChanged . Remove ( OnClampChangedDelegateHandle ) ;
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
{
2022-09-22 15:02:24 -04:00
if ( const UMetasoundEditorGraphMember * Member = Cast < UMetasoundEditorGraphMember > ( FloatLiteral - > GetOuter ( ) ) )
{
MetasoundAsset - > GetModifyContext ( ) . AddMemberIDsModified ( { Member - > GetMemberID ( ) } ) ;
}
2021-10-12 21:21:22 -04:00
}
}
} ) ;
2022-01-14 14:01:09 -05:00
if ( bShouldClampDefaultValue )
{
2022-02-09 12:52:07 -05:00
IDetailPropertyRow * RangeRow = DefaultCategoryBuilder - > AddExternalObjectProperty ( TArray < UObject * > ( { DefaultFloat } ) , GET_MEMBER_NAME_CHECKED ( UMetasoundEditorGraphMemberDefaultFloat , Range ) ) ;
if ( ensure ( RangeRow ) )
{
DefaultRows . Add ( RangeRow ) ;
}
2022-01-14 14:01:09 -05:00
}
}
2022-06-16 12:30:27 -04:00
// Enable widget options for editable inputs only
bool bShowWidgetOptions = false ;
if ( const UMetasoundEditorGraphInput * ParentMember = Cast < UMetasoundEditorGraphInput > ( InLiteral . GetParentMember ( ) ) )
2022-01-14 14:01:09 -05:00
{
if ( const UMetasoundEditorGraph * OwningGraph = ParentMember - > GetOwningGraph ( ) )
{
2022-07-18 17:14:25 -04:00
// Disable widget options for constructor inputs for now to prevent changing default value via widget while playing
bShowWidgetOptions = OwningGraph - > IsEditable ( ) & & ParentMember - > GetVertexAccessType ( ) = = EMetasoundFrontendVertexAccessType : : Reference ;
2022-01-14 14:01:09 -05:00
}
2021-10-12 21:21:22 -04:00
}
2022-01-04 15:17:54 -05:00
// add input widget properties
2022-06-16 12:30:27 -04:00
if ( bShowWidgetOptions )
2022-01-14 14:01:09 -05:00
{
IDetailCategoryBuilder & WidgetCategoryBuilder = InDetailLayout . EditCategory ( " EditorOptions " ) ;
2022-02-09 12:52:07 -05:00
DefaultRows . Add ( WidgetCategoryBuilder . AddExternalObjectProperty ( TArray < UObject * > ( { DefaultFloat } ) , GET_MEMBER_NAME_CHECKED ( UMetasoundEditorGraphMemberDefaultFloat , WidgetType ) ) ) ;
DefaultRows . Add ( WidgetCategoryBuilder . AddExternalObjectProperty ( TArray < UObject * > ( { DefaultFloat } ) , GET_MEMBER_NAME_CHECKED ( UMetasoundEditorGraphMemberDefaultFloat , WidgetOrientation ) ) ) ;
DefaultRows . Add ( WidgetCategoryBuilder . AddExternalObjectProperty ( TArray < UObject * > ( { DefaultFloat } ) , GET_MEMBER_NAME_CHECKED ( UMetasoundEditorGraphMemberDefaultFloat , WidgetValueType ) ) ) ;
2022-10-26 10:53:25 -04:00
if ( DefaultFloat - > WidgetType ! = EMetasoundMemberDefaultWidget : : None & & DefaultFloat - > WidgetValueType = = EMetasoundMemberDefaultWidgetValueType : : Volume )
2022-01-14 14:01:09 -05:00
{
2022-02-09 12:52:07 -05:00
DefaultRows . Add ( WidgetCategoryBuilder . AddExternalObjectProperty ( TArray < UObject * > ( { DefaultFloat } ) , GET_MEMBER_NAME_CHECKED ( UMetasoundEditorGraphMemberDefaultFloat , VolumeWidgetUseLinearOutput ) ) ) ;
2022-10-19 15:34:44 -04:00
if ( DefaultFloat - > VolumeWidgetUseLinearOutput )
{
DefaultRows . Add ( WidgetCategoryBuilder . AddExternalObjectProperty ( TArray < UObject * > ( { DefaultFloat } ) , GET_MEMBER_NAME_CHECKED ( UMetasoundEditorGraphMemberDefaultFloat , VolumeWidgetDecibelRange ) ) ) ;
}
2022-01-14 14:01:09 -05:00
}
}
2022-02-09 12:52:07 -05:00
return DefaultRows ;
2021-03-23 17:55:31 -04:00
}
2022-02-09 12:52:07 -05:00
TArray < IDetailPropertyRow * > FMetasoundObjectArrayLiteralCustomization : : CustomizeLiteral ( UMetasoundEditorGraphMemberDefaultLiteral & InLiteral , IDetailLayoutBuilder & InDetailLayout )
2021-03-23 17:55:31 -04:00
{
2022-01-04 15:17:54 -05:00
check ( DefaultCategoryBuilder ) ;
2021-03-23 17:55:31 -04:00
2022-01-04 15:17:54 -05:00
TSharedPtr < IPropertyHandle > DefaultValueHandle ;
IDetailPropertyRow * Row = DefaultCategoryBuilder - > AddExternalObjectProperty ( TArray < UObject * > ( { & InLiteral } ) , GET_MEMBER_NAME_CHECKED ( UMetasoundEditorGraphMemberDefaultObjectArray , Default ) ) ;
if ( ensure ( Row ) )
2021-03-23 17:55:31 -04:00
{
2022-01-04 15:17:54 -05:00
DefaultValueHandle = Row - > GetPropertyHandle ( ) ;
2021-03-23 17:55:31 -04:00
}
2022-01-04 15:17:54 -05:00
constexpr bool bShowChildren = true ;
Row - > ShowPropertyButtons ( false )
. CustomWidget ( bShowChildren )
. NameContent ( )
[
DefaultValueHandle - > CreatePropertyNameWidget ( )
]
. ValueContent ( )
[
SNew ( SAssetDropTarget )
. bSupportsMultiDrop ( true )
. OnAreAssetsAcceptableForDropWithReason_Lambda ( [ this , DefaultValueHandle ] ( TArrayView < FAssetData > InAssets , FText & OutReason )
{
Frontend : : FDataTypeRegistryInfo DataTypeInfo ;
MemberCustomizationPrivate : : GetDataTypeFromElementPropertyHandle ( DefaultValueHandle , DataTypeInfo ) ;
const IMetasoundEditorModule & EditorModule = FModuleManager : : GetModuleChecked < IMetasoundEditorModule > ( " MetaSoundEditor " ) ;
2022-07-14 17:51:07 -04:00
bool bCanDrop = false ;
if ( UClass * ProxyGenClass = DataTypeInfo . ProxyGeneratorClass )
2022-01-04 15:17:54 -05:00
{
2022-07-14 17:51:07 -04:00
bCanDrop = true ;
for ( const FAssetData & AssetData : InAssets )
2022-01-04 15:17:54 -05:00
{
if ( UClass * Class = AssetData . GetClass ( ) )
{
2023-05-26 13:55:21 -04:00
PRAGMA_DISABLE_DEPRECATION_WARNINGS
2022-01-04 15:17:54 -05:00
if ( EditorModule . IsExplicitProxyClass ( * DataTypeInfo . ProxyGeneratorClass ) )
2023-05-26 13:55:21 -04:00
{
bCanDrop & = Class = = DataTypeInfo . ProxyGeneratorClass ;
continue ;
}
PRAGMA_ENABLE_DEPRECATION_WARNINGS
if ( DataTypeInfo . bIsExplicit )
2022-01-04 15:17:54 -05:00
{
bCanDrop & = Class = = DataTypeInfo . ProxyGeneratorClass ;
}
else
{
bCanDrop & = Class - > IsChildOf ( DataTypeInfo . ProxyGeneratorClass ) ;
}
}
}
}
2022-07-14 17:51:07 -04:00
return bCanDrop ;
2022-01-04 15:17:54 -05:00
} )
. OnAssetsDropped_Lambda ( [ this , DefaultValueHandle ] ( const FDragDropEvent & DragDropEvent , TArrayView < FAssetData > InAssets )
{
if ( DefaultValueHandle . IsValid ( ) )
{
TSharedPtr < IPropertyHandleArray > ArrayHandle = DefaultValueHandle - > AsArray ( ) ;
if ( ensure ( ArrayHandle . IsValid ( ) ) )
{
for ( const FAssetData & AssetData : InAssets )
{
uint32 AddIndex = INDEX_NONE ;
ArrayHandle - > GetNumElements ( AddIndex ) ;
ArrayHandle - > AddItem ( ) ;
TSharedPtr < IPropertyHandle > ElementHandle = ArrayHandle - > GetElement ( static_cast < int32 > ( AddIndex ) ) ;
TSharedPtr < IPropertyHandle > ObjectHandle = ElementHandle - > GetChildHandle ( GET_MEMBER_NAME_CHECKED ( FMetasoundEditorGraphMemberDefaultObjectRef , Object ) ) ;
ObjectHandle - > SetValue ( AssetData . GetAsset ( ) ) ;
}
}
}
} )
[
DefaultValueHandle - > CreatePropertyValueWidget ( )
]
] ;
2022-02-09 12:52:07 -05:00
return { Row } ;
2021-03-23 17:55:31 -04:00
}
2021-12-13 18:15:01 -05:00
FText FMetasoundMemberDefaultBoolDetailCustomization : : GetPropertyNameOverride ( ) const
2021-03-23 17:55:31 -04:00
{
2022-01-04 15:17:54 -05:00
using namespace MemberCustomizationPrivate ;
if ( GetPrimitiveTypeName ( DataTypeInfo ) = = Metasound : : GetMetasoundDataTypeName < Metasound : : FTrigger > ( ) )
2021-03-23 17:55:31 -04:00
{
return LOCTEXT ( " TriggerInput_SimulateTitle " , " Simulate " ) ;
}
return FText : : GetEmpty ( ) ;
}
2021-12-13 18:15:01 -05:00
TSharedRef < SWidget > FMetasoundMemberDefaultBoolDetailCustomization : : CreateStructureWidget ( TSharedPtr < IPropertyHandle > & StructPropertyHandle ) const
2021-03-23 17:55:31 -04:00
{
using namespace Frontend ;
2022-01-04 15:17:54 -05:00
using namespace MemberCustomizationPrivate ;
2021-03-23 17:55:31 -04:00
2021-12-13 18:15:01 -05:00
TSharedPtr < IPropertyHandle > ValueProperty = StructPropertyHandle - > GetChildHandle ( GET_MEMBER_NAME_CHECKED ( FMetasoundEditorGraphMemberDefaultBoolRef , Value ) ) ;
if ( ValueProperty . IsValid ( ) )
2021-03-23 17:55:31 -04:00
{
2021-12-13 18:15:01 -05:00
// Not a trigger, so just display as underlying literal type (bool)
2022-01-04 15:17:54 -05:00
if ( GetPrimitiveTypeName ( DataTypeInfo ) ! = Metasound : : GetMetasoundDataTypeName < Metasound : : FTrigger > ( ) )
2021-03-23 17:55:31 -04:00
{
2021-12-13 18:15:01 -05:00
return ValueProperty - > CreatePropertyValueWidget ( ) ;
}
2021-03-23 17:55:31 -04:00
2021-12-13 18:15:01 -05:00
TAttribute < bool > EnablementAttribute = false ;
TAttribute < EVisibility > VisibilityAttribute = EVisibility : : Visible ;
TArray < UObject * > OuterObjects ;
ValueProperty - > GetOuterObjects ( OuterObjects ) ;
if ( ! OuterObjects . IsEmpty ( ) )
{
if ( UMetasoundEditorGraphMemberDefaultLiteral * Literal = Cast < UMetasoundEditorGraphMemberDefaultLiteral > ( OuterObjects . Last ( ) ) )
2021-04-07 02:59:10 -04:00
{
2021-12-13 18:15:01 -05:00
if ( UMetasoundEditorGraphInput * Input = Cast < UMetasoundEditorGraphInput > ( Literal - > GetParentMember ( ) ) )
2021-04-07 02:59:10 -04:00
{
2021-12-13 18:15:01 -05:00
// Don't display trigger simulation widget if its a trigger
// provided by an interface that does not support transmission.
const FInterfaceRegistryKey Key = GetInterfaceRegistryKey ( Input - > GetInterfaceVersion ( ) ) ;
const IInterfaceRegistryEntry * Entry = IInterfaceRegistry : : Get ( ) . FindInterfaceRegistryEntry ( Key ) ;
if ( ! Entry | | Entry - > GetRouterName ( ) = = Audio : : IParameterTransmitter : : RouterName )
{
EnablementAttribute = true ;
return SMetaSoundGraphNode : : CreateTriggerSimulationWidget ( * Literal , MoveTemp ( VisibilityAttribute ) , MoveTemp ( EnablementAttribute ) ) ;
}
const FText DisabledToolTip = LOCTEXT ( " NonTransmittibleInputTriggerSimulationDisabledTooltip " , " Trigger simulation disabled: Parent interface does not support being updated by game thread parameters. " ) ;
return SMetaSoundGraphNode : : CreateTriggerSimulationWidget ( * Literal , MoveTemp ( VisibilityAttribute ) , MoveTemp ( EnablementAttribute ) , & DisabledToolTip ) ;
2021-04-07 02:59:10 -04:00
}
}
2021-03-23 17:55:31 -04:00
}
}
return SNullWidget : : NullWidget ;
2021-03-19 15:10:57 -04:00
}
2021-12-13 18:15:01 -05:00
TSharedRef < SWidget > FMetasoundMemberDefaultIntDetailCustomization : : CreateStructureWidget ( TSharedPtr < IPropertyHandle > & StructPropertyHandle ) const
2021-03-19 15:10:57 -04:00
{
using namespace Frontend ;
2022-01-04 15:17:54 -05:00
using namespace MemberCustomizationPrivate ;
2021-03-19 15:10:57 -04:00
if ( FMetasoundFrontendRegistryContainer * Registry = FMetasoundFrontendRegistryContainer : : Get ( ) )
{
2021-12-13 18:15:01 -05:00
TSharedPtr < IPropertyHandle > ValueProperty = StructPropertyHandle - > GetChildHandle ( GET_MEMBER_NAME_CHECKED ( FMetasoundEditorGraphMemberDefaultIntRef , Value ) ) ;
2021-03-19 15:10:57 -04:00
if ( ValueProperty . IsValid ( ) )
{
2022-01-04 15:17:54 -05:00
TSharedPtr < const IEnumDataTypeInterface > EnumInterface = IDataTypeRegistry : : Get ( ) . GetEnumInterfaceForDataType ( GetPrimitiveTypeName ( DataTypeInfo ) ) ;
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 ;
}
2021-12-13 18:15:01 -05:00
TSharedRef < SWidget > FMetasoundMemberDefaultObjectDetailCustomization : : CreateStructureWidget ( TSharedPtr < IPropertyHandle > & StructPropertyHandle ) const
2021-03-19 15:10:57 -04:00
{
2021-12-13 18:15:01 -05:00
TSharedPtr < IPropertyHandle > PropertyHandle = StructPropertyHandle - > GetChildHandle ( GET_MEMBER_NAME_CHECKED ( FMetasoundEditorGraphMemberDefaultObjectRef , Object ) ) ;
2021-03-19 15:10:57 -04:00
2021-11-07 23:43:01 -05:00
const IMetasoundEditorModule & EditorModule = FModuleManager : : GetModuleChecked < IMetasoundEditorModule > ( " MetaSoundEditor " ) ;
2023-05-26 13:55:21 -04:00
auto FilterAsset = [ InEditorModule = & EditorModule , & InDataTypeInfo = DataTypeInfo ] ( const FAssetData & InAsset )
2021-03-19 15:10:57 -04:00
{
2023-05-26 13:55:21 -04:00
if ( InDataTypeInfo . ProxyGeneratorClass )
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
{
2023-05-26 13:55:21 -04:00
PRAGMA_DISABLE_DEPRECATION_WARNINGS
if ( InEditorModule - > IsExplicitProxyClass ( * InDataTypeInfo . ProxyGeneratorClass ) )
2021-11-07 23:43:01 -05:00
{
2023-05-26 13:55:21 -04:00
return Class ! = InDataTypeInfo . ProxyGeneratorClass ;
}
PRAGMA_ENABLE_DEPRECATION_WARNINGS
if ( InDataTypeInfo . bIsExplicit )
{
return Class ! = InDataTypeInfo . ProxyGeneratorClass ;
2021-11-07 23:43:01 -05:00
}
2023-05-26 13:55:21 -04:00
return ! Class - > IsChildOf ( InDataTypeInfo . ProxyGeneratorClass ) ;
2021-03-19 15:10:57 -04:00
}
}
2021-11-07 23:43:01 -05:00
return true ;
} ;
auto ValidateAsset = [ FilterAsset ] ( const FAssetData & InAsset )
{
2022-01-04 15:17:54 -05:00
// A null asset reference is a valid default
return InAsset . IsValid ( ) ? ! FilterAsset ( InAsset ) : true ;
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 )
2022-01-04 15:17:54 -05:00
. AllowedClass ( DataTypeInfo . ProxyGeneratorClass )
2021-03-19 15:10:57 -04:00
. DisplayBrowse ( true )
. DisplayThumbnail ( true )
2021-08-18 15:16:57 -04:00
. DisplayUseSelected ( true )
2022-01-04 15:17:54 -05:00
. NewAssetFactories ( PropertyCustomizationHelpers : : GetNewAssetFactoriesForClasses ( { DataTypeInfo . ProxyGeneratorClass } ) )
2021-08-18 15:16:57 -04:00
. ObjectPath_Lambda ( GetAssetPath )
. OnShouldFilterAsset_Lambda ( FilterAsset )
. OnShouldSetAsset_Lambda ( ValidateAsset )
. PropertyHandle ( PropertyHandle ) ;
2021-03-19 15:10:57 -04:00
}
2022-01-04 15:17:54 -05:00
TSharedRef < SWidget > FMetasoundDefaultMemberElementDetailCustomizationBase : : CreateNameWidget ( TSharedPtr < IPropertyHandle > StructPropertyHandle ) const
2021-03-23 17:55:31 -04:00
{
const FText PropertyName = GetPropertyNameOverride ( ) ;
if ( ! PropertyName . IsEmpty ( ) )
{
return SNew ( STextBlock )
. Font ( IDetailLayoutBuilder : : GetDetailFont ( ) )
. Text ( PropertyName ) ;
}
return SNew ( STextBlock )
2021-12-13 18:15:01 -05:00
. Text ( MemberCustomizationStyle : : DefaultPropertyText )
2021-03-23 17:55:31 -04:00
. Font ( IDetailLayoutBuilder : : GetDetailFont ( ) ) ;
}
2022-01-04 15:17:54 -05:00
TSharedRef < SWidget > FMetasoundDefaultMemberElementDetailCustomizationBase : : CreateValueWidget ( TSharedPtr < IPropertyHandleArray > ParentPropertyHandleArray , TSharedPtr < IPropertyHandle > StructPropertyHandle ) const
2021-03-19 15:10:57 -04:00
{
2021-03-23 17:55:31 -04:00
TSharedRef < SWidget > ValueWidget = CreateStructureWidget ( StructPropertyHandle ) ;
2022-01-04 15:17:54 -05:00
if ( ! ParentPropertyHandleArray . IsValid ( ) )
2021-03-19 15:10:57 -04:00
{
2021-03-23 17:55:31 -04:00
return ValueWidget ;
2021-03-19 15:10:57 -04:00
}
TSharedPtr < IPropertyHandle > StructPropertyPtr = StructPropertyHandle ;
2022-01-04 15:17:54 -05:00
FExecuteAction InsertAction = FExecuteAction : : CreateLambda ( [ ParentPropertyHandleArray , StructPropertyPtr ]
2021-03-19 15:10:57 -04:00
{
const int32 ArrayIndex = StructPropertyPtr . IsValid ( ) ? StructPropertyPtr - > GetIndexInArray ( ) : INDEX_NONE ;
2022-01-04 15:17:54 -05:00
if ( ParentPropertyHandleArray . IsValid ( ) & & ArrayIndex > = 0 )
2021-03-19 15:10:57 -04:00
{
2022-01-04 15:17:54 -05:00
ParentPropertyHandleArray - > Insert ( ArrayIndex ) ;
2021-03-19 15:10:57 -04:00
}
} ) ;
2022-01-04 15:17:54 -05:00
FExecuteAction DeleteAction = FExecuteAction : : CreateLambda ( [ ParentPropertyHandleArray , StructPropertyPtr ]
2021-03-19 15:10:57 -04:00
{
const int32 ArrayIndex = StructPropertyPtr . IsValid ( ) ? StructPropertyPtr - > GetIndexInArray ( ) : INDEX_NONE ;
2022-01-04 15:17:54 -05:00
if ( ParentPropertyHandleArray . IsValid ( ) & & ArrayIndex > = 0 )
2021-03-19 15:10:57 -04:00
{
2022-01-04 15:17:54 -05:00
ParentPropertyHandleArray - > DeleteItem ( ArrayIndex ) ;
2021-03-19 15:10:57 -04:00
}
} ) ;
2022-01-04 15:17:54 -05:00
FExecuteAction DuplicateAction = FExecuteAction : : CreateLambda ( [ ParentPropertyHandleArray , StructPropertyPtr ]
2021-03-19 15:10:57 -04:00
{
const int32 ArrayIndex = StructPropertyPtr . IsValid ( ) ? StructPropertyPtr - > GetIndexInArray ( ) : INDEX_NONE ;
2022-01-04 15:17:54 -05:00
if ( ParentPropertyHandleArray . IsValid ( ) & & ArrayIndex > = 0 )
2021-03-19 15:10:57 -04:00
{
2022-01-04 15:17:54 -05:00
ParentPropertyHandleArray - > DuplicateItem ( ArrayIndex ) ;
2021-03-19 15:10:57 -04:00
}
} ) ;
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 )
] ;
}
2022-01-04 15:17:54 -05:00
void FMetasoundDefaultMemberElementDetailCustomizationBase : : CustomizeChildren ( TSharedRef < IPropertyHandle > StructPropertyHandle , IDetailChildrenBuilder & ChildBuilder , IPropertyTypeCustomizationUtils & StructCustomizationUtils )
2021-03-19 15:10:57 -04:00
{
2022-01-04 15:17:54 -05:00
TSharedPtr < IPropertyHandleArray > ParentPropertyHandleArray ;
TSharedPtr < IPropertyHandle > ElementPropertyHandle = StructPropertyHandle ;
if ( ElementPropertyHandle . IsValid ( ) )
2021-03-19 15:10:57 -04:00
{
2022-01-04 15:17:54 -05:00
TSharedPtr < IPropertyHandle > ParentProperty = ElementPropertyHandle - > GetParentHandle ( ) ;
while ( ParentProperty . IsValid ( ) & & ParentProperty - > GetProperty ( ) ! = nullptr )
2021-03-19 15:10:57 -04:00
{
2022-01-04 15:17:54 -05:00
ParentPropertyHandleArray = ParentProperty - > AsArray ( ) ;
if ( ParentPropertyHandleArray . IsValid ( ) )
2021-03-19 15:10:57 -04:00
{
2022-01-04 15:17:54 -05:00
ElementPropertyHandle = ParentProperty ;
break ;
2021-03-19 15:10:57 -04:00
}
}
}
2022-07-14 17:51:07 -04:00
2022-01-04 15:17:54 -05:00
MemberCustomizationPrivate : : GetDataTypeFromElementPropertyHandle ( ElementPropertyHandle , DataTypeInfo ) ;
2021-03-19 15:10:57 -04:00
2022-01-04 15:17:54 -05:00
TSharedRef < SWidget > ValueWidget = CreateValueWidget ( ParentPropertyHandleArray , StructPropertyHandle ) ;
2021-12-13 18:15:01 -05:00
FDetailWidgetRow & ValueRow = ChildBuilder . AddCustomRow ( MemberCustomizationStyle : : DefaultPropertyText ) ;
2022-01-04 15:17:54 -05:00
if ( ParentPropertyHandleArray . IsValid ( ) )
2021-03-19 15:10:57 -04:00
{
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-12-13 18:15:01 -05:00
FSimpleDelegate UpdateFrontendDefaultLiteral = FSimpleDelegate : : CreateLambda ( [ InInputs = Inputs ] ( )
2021-03-19 15:10:57 -04:00
{
for ( const TWeakObjectPtr < UMetasoundEditorGraphInput > & GraphInput : InInputs )
{
if ( GraphInput . IsValid ( ) )
{
2021-12-13 18:15:01 -05:00
constexpr bool bPostTransaction = true ;
GraphInput - > UpdateFrontendDefaultLiteral ( bPostTransaction ) ;
2021-03-19 15:10:57 -04:00
}
}
} ) ;
2021-12-13 18:15:01 -05:00
StructPropertyHandle - > SetOnChildPropertyValueChanged ( UpdateFrontendDefaultLiteral ) ;
2021-03-19 15:10:57 -04:00
ValueRow . ValueContent ( )
[
ValueWidget
] ;
}
2022-01-04 15:17:54 -05:00
void FMetasoundDefaultMemberElementDetailCustomizationBase : : CustomizeHeader ( TSharedRef < IPropertyHandle > StructPropertyHandle , FDetailWidgetRow & HeaderRow , IPropertyTypeCustomizationUtils & StructCustomizationUtils )
2021-03-19 15:10:57 -04:00
{
}
2021-11-07 23:43:01 -05:00
FName FMetasoundDataTypeSelector : : GetDataType ( ) const
{
if ( GraphMember . IsValid ( ) )
{
2021-12-13 18:15:01 -05:00
return GraphMember - > GetDataType ( ) ;
2021-11-07 23:43:01 -05:00
}
return FName ( ) ;
}
void FMetasoundDataTypeSelector : : OnDataTypeSelected ( FName InSelectedTypeName )
{
FName NewDataTypeName ;
2021-12-13 18:15:01 -05:00
FName ArrayDataTypeName = CreateArrayTypeNameFromElementTypeName ( InSelectedTypeName ) ;
2021-11-07 23:43:01 -05:00
// 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.
if ( DataTypeArrayCheckbox - > GetCheckedState ( ) = = ECheckBoxState : : Checked )
{
2022-05-19 15:24:49 -04:00
if ( Frontend : : IDataTypeRegistry : : Get ( ) . IsRegistered ( ArrayDataTypeName ) )
2021-11-07 23:43:01 -05:00
{
NewDataTypeName = ArrayDataTypeName ;
}
else
{
2022-05-19 15:24:49 -04:00
ensure ( Frontend : : IDataTypeRegistry : : Get ( ) . IsRegistered ( InSelectedTypeName ) ) ;
2021-11-07 23:43:01 -05:00
NewDataTypeName = InSelectedTypeName ;
}
}
else
{
2022-05-19 15:24:49 -04:00
if ( Frontend : : IDataTypeRegistry : : Get ( ) . IsRegistered ( InSelectedTypeName ) )
2021-11-07 23:43:01 -05:00
{
NewDataTypeName = InSelectedTypeName ;
}
else
{
2022-05-19 15:24:49 -04:00
ensure ( Frontend : : IDataTypeRegistry : : Get ( ) . IsRegistered ( ArrayDataTypeName ) ) ;
2021-11-07 23:43:01 -05:00
NewDataTypeName = ArrayDataTypeName ;
}
}
2021-12-13 18:15:01 -05:00
if ( NewDataTypeName = = GraphMember - > GetDataType ( ) )
2021-11-07 23:43:01 -05:00
{
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 ) ;
2021-12-13 18:15:01 -05:00
}
2021-11-07 23:43:01 -05:00
}
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-12-13 18:15:01 -05:00
using namespace Frontend ;
2021-11-07 23:43:01 -05:00
if ( ! InGraphMember . IsValid ( ) )
{
return ;
}
GraphMember = InGraphMember ;
2021-03-19 15:10:57 -04:00
2021-12-13 18:15:01 -05:00
FDataTypeRegistryInfo DataTypeInfo ;
if ( ! ensure ( IDataTypeRegistry : : Get ( ) . GetDataTypeInfo ( InGraphMember - > GetDataType ( ) , DataTypeInfo ) ) )
2021-03-19 15:10:57 -04:00
{
2021-12-13 18:15:01 -05:00
return ;
}
2022-07-14 17:51:07 -04:00
if ( DataTypeInfo . bIsArrayType )
2021-12-13 18:15:01 -05:00
{
ArrayTypeName = GraphMember - > GetDataType ( ) ;
BaseTypeName = CreateElementTypeNameFromArrayTypeName ( InGraphMember - > GetDataType ( ) ) ;
}
else
{
ArrayTypeName = CreateArrayTypeNameFromElementTypeName ( InGraphMember - > GetDataType ( ) ) ;
BaseTypeName = GraphMember - > GetDataType ( ) ;
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
2021-12-13 18:15:01 -05:00
// types should have the "Is Array" checkbox disabled.
2022-07-14 17:51:07 -04:00
const bool bIsArrayTypeRegistered = IDataTypeRegistry : : Get ( ) . IsRegistered ( ArrayTypeName ) ;
2021-12-13 18:15:01 -05:00
const bool bIsArrayTypeRegisteredHidden = MemberCustomizationPrivate : : HiddenInputTypeNames . Contains ( ArrayTypeName ) ;
2021-04-06 21:02:21 -04:00
2021-12-02 14:23:45 -05:00
TArray < FName > BaseDataTypes ;
2021-12-13 18:15:01 -05:00
IDataTypeRegistry : : Get ( ) . IterateDataTypeInfo ( [ & BaseDataTypes ] ( const FDataTypeRegistryInfo & RegistryInfo )
2021-03-19 15:10:57 -04:00
{
2022-07-14 17:51:07 -04:00
// Hide the type from the combo selector if any of the following is true
2021-12-13 18:15:01 -05:00
const bool bIsHiddenType = MemberCustomizationPrivate : : HiddenInputTypeNames . Contains ( RegistryInfo . DataTypeName ) ;
2022-07-14 17:51:07 -04:00
const bool bHideBaseType = RegistryInfo . bIsArrayType | | RegistryInfo . bIsVariable | | bIsHiddenType ;
2021-12-02 14:23:45 -05:00
if ( ! bHideBaseType )
2021-03-19 15:10:57 -04:00
{
2021-12-13 18:15:01 -05:00
BaseDataTypes . Add ( RegistryInfo . DataTypeName ) ;
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 )
2022-04-25 13:29:29 -04:00
. Font ( IDetailLayoutBuilder : : GetDetailFontBold ( ) )
2021-03-19 15:10:57 -04:00
]
. 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 ] ( )
{
2021-12-13 18:15:01 -05:00
return FText : : FromName ( BaseTypeName ) ;
2021-11-07 23:43:01 -05:00
} )
]
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
2021-12-13 18:15:01 -05:00
auto NameMatchesPredicate = [ TypeString = BaseTypeName . ToString ( ) ] ( const TSharedPtr < FString > & Item ) { return * Item = = TypeString ; } ;
2021-11-07 23:43:01 -05:00
const TSharedPtr < FString > * SelectedItem = ComboOptions . FindByPredicate ( NameMatchesPredicate ) ;
if ( ensure ( SelectedItem ) )
{
2022-03-22 14:01:46 -04:00
DataTypeComboBox - > SetSelectedItem ( * SelectedItem , ESelectInfo : : Direct ) ;
2021-11-07 23:43:01 -05:00
}
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-12-13 18:15:01 -05:00
using namespace Frontend ;
2021-10-25 20:05:28 -04:00
if ( InGraphMember . IsValid ( ) )
2021-03-19 15:10:57 -04:00
{
2021-12-13 18:15:01 -05:00
FDataTypeRegistryInfo DataTypeInfo ;
if ( ensure ( IDataTypeRegistry : : Get ( ) . GetDataTypeInfo ( InGraphMember - > GetDataType ( ) , DataTypeInfo ) ) )
{
2022-07-14 17:51:07 -04:00
return DataTypeInfo . bIsArrayType ? ECheckBoxState : : Checked : ECheckBoxState : : Unchecked ;
2021-12-13 18:15:01 -05:00
}
2021-03-19 15:10:57 -04:00
}
return ECheckBoxState : : Undetermined ;
}
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 ( ) ) )
{
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-12-13 18:15:01 -05:00
const FName DataType = InNewState = = ECheckBoxState : : Checked ? ArrayTypeName : BaseTypeName ;
InGraphMember - > SetDataType ( DataType ) ;
2021-03-19 15:10:57 -04:00
}
}
}
2022-04-06 14:52:43 -04:00
void FMetasoundMemberDetailCustomization : : UpdateRenameDelegate ( UMetasoundEditorGraphMember & InMember )
2022-03-01 16:31:55 -05:00
{
2022-04-06 14:52:43 -04:00
if ( InMember . CanRename ( ) )
2022-03-01 16:31:55 -05:00
{
2022-04-06 14:52:43 -04:00
if ( ! RenameRequestedHandle . IsValid ( ) )
2022-03-01 16:31:55 -05:00
{
2022-04-06 14:52:43 -04:00
InMember . OnRenameRequested . Clear ( ) ;
RenameRequestedHandle = InMember . OnRenameRequested . AddLambda ( [ this ] ( )
2022-03-01 16:31:55 -05:00
{
2022-04-06 14:52:43 -04:00
FSlateApplication : : Get ( ) . SetKeyboardFocus ( NameEditableTextBox . ToSharedRef ( ) , EFocusCause : : SetDirectly ) ;
} ) ;
2022-03-01 16:31:55 -05:00
}
}
}
void FMetasoundMemberDetailCustomization : : CacheMemberData ( IDetailLayoutBuilder & InDetailLayout )
{
TArray < TWeakObjectPtr < UObject > > Objects ;
InDetailLayout . GetObjectsBeingCustomized ( Objects ) ;
if ( ! Objects . IsEmpty ( ) )
{
GraphMember = Cast < UMetasoundEditorGraphMember > ( Objects . Last ( ) . Get ( ) ) ;
TSharedPtr < IPropertyHandle > LiteralHandle = InDetailLayout . GetProperty ( UMetasoundEditorGraphMember : : GetLiteralPropertyName ( ) ) ;
if ( ensure ( GraphMember . IsValid ( ) ) & & ensure ( LiteralHandle . IsValid ( ) ) )
{
// Always hide, even if no customization (LiteralObject isn't found) as this is the case
// where the default object is not required (i.e. Default Member is default constructed)
LiteralHandle - > MarkHiddenByCustomization ( ) ;
}
}
}
TArray < IDetailPropertyRow * > FMetasoundMemberDetailCustomization : : CustomizeDefaultCategory ( IDetailLayoutBuilder & InDetailLayout )
{
TArray < IDetailPropertyRow * > DefaultPropertyRows ;
if ( ! GraphMember . IsValid ( ) )
{
return DefaultPropertyRows ;
}
2022-04-06 14:52:43 -04:00
UpdateRenameDelegate ( * GraphMember ) ;
2022-03-01 16:31:55 -05:00
if ( UMetasoundEditorGraphMemberDefaultLiteral * MemberDefaultLiteral = GraphMember - > GetLiteral ( ) )
{
UClass * MemberClass = MemberDefaultLiteral - > GetClass ( ) ;
check ( MemberClass ) ;
IDetailCategoryBuilder & DefaultCategoryBuilder = GetDefaultCategoryBuilder ( InDetailLayout ) ;
IMetasoundEditorModule & EditorModule = FModuleManager : : GetModuleChecked < IMetasoundEditorModule > ( " MetaSoundEditor " ) ;
TUniquePtr < FMetasoundDefaultLiteralCustomizationBase > LiteralCustomization = EditorModule . CreateMemberDefaultLiteralCustomization ( * MemberClass , DefaultCategoryBuilder ) ;
if ( LiteralCustomization . IsValid ( ) )
{
DefaultPropertyRows = LiteralCustomization - > CustomizeLiteral ( * MemberDefaultLiteral , InDetailLayout ) ;
}
else
{
IDetailPropertyRow * DefaultPropertyRow = DefaultCategoryBuilder . AddExternalObjectProperty ( TArray < UObject * > ( { MemberDefaultLiteral } ) , " Default " ) ;
ensureMsgf ( DefaultPropertyRow , TEXT ( " Class '%s' missing expected 'Default' member. "
" Either add/rename default member or register customization to display default value/opt out appropriately. " ) ,
* MemberClass - > GetName ( ) ) ;
DefaultPropertyRows . Add ( DefaultPropertyRow ) ;
}
}
2022-03-04 03:48:32 -05:00
for ( IDetailPropertyRow * Row : DefaultPropertyRows )
{
if ( ensure ( Row ) )
{
Row - > Visibility ( TAttribute < EVisibility > : : CreateLambda ( [ this ] ( )
{
return GetDefaultVisibility ( ) ;
} ) ) ;
}
}
2022-03-01 16:31:55 -05:00
return DefaultPropertyRows ;
}
void FMetasoundMemberDetailCustomization : : CustomizeGeneralCategory ( IDetailLayoutBuilder & InDetailLayout )
{
IDetailCategoryBuilder & CategoryBuilder = GetGeneralCategoryBuilder ( InDetailLayout ) ;
2024-02-01 19:54:42 -05:00
const bool bIsReadOnly = IsInterfaceMember ( ) | | ! IsGraphEditable ( ) ;
// Override row copy action if it's disabled by the edit condition
auto GenerateCopyPasteActions = [ ] ( FDetailWidgetRow & Row , const FString & Value )
{
FUIAction CopyAction ( FExecuteAction : : CreateLambda ( [ Value ] ( )
{
FPlatformApplicationMisc : : ClipboardCopy ( * Value ) ;
} ) ) ;
Row . CopyAction ( CopyAction ) ;
// Create a dummy paste action
// Needed because the custom copy action will only be set
// if both the copy and paste actions are bound
// Pasting is still available directly via the text box if editable
const static FUIAction PasteAction ( FExecuteAction : : CreateLambda ( [ ] ( ) { } ) , FCanExecuteAction : : CreateLambda ( [ ] ( ) { return false ; } ) ) ;
Row . PasteAction ( PasteAction ) ;
} ;
2022-03-01 16:31:55 -05:00
NameEditableTextBox = SNew ( SEditableTextBox )
. Text ( this , & FMetasoundMemberDetailCustomization : : GetName )
. OnTextChanged ( this , & FMetasoundMemberDetailCustomization : : OnNameChanged )
. OnTextCommitted ( this , & FMetasoundMemberDetailCustomization : : OnNameCommitted )
2024-02-01 19:54:42 -05:00
. IsReadOnly ( bIsReadOnly )
2022-03-01 16:31:55 -05:00
. SelectAllTextWhenFocused ( true )
. Font ( IDetailLayoutBuilder : : GetDetailFont ( ) ) ;
static const FText MemberNameToolTipFormat = LOCTEXT ( " GraphMember_NameDescriptionFormat " , " Name used within the MetaSounds editor(s) and transacting systems (ex. Blueprints) if applicable to reference the given {0}. " ) ;
2024-02-01 19:54:42 -05:00
FDetailWidgetRow & NameRow = CategoryBuilder . AddCustomRow ( LOCTEXT ( " GraphMember_NameProperty " , " Name " ) )
. EditCondition ( ! bIsReadOnly , nullptr )
2022-03-01 16:31:55 -05:00
. NameContent ( )
[
SNew ( STextBlock )
. Font ( IDetailLayoutBuilder : : GetDetailFontBold ( ) )
. Text ( GraphMember - > GetGraphMemberLabel ( ) )
. ToolTipText ( FText : : Format ( MemberNameToolTipFormat , GraphMember - > GetGraphMemberLabel ( ) ) )
]
. ValueContent ( )
[
NameEditableTextBox . ToSharedRef ( )
] ;
2024-02-01 19:54:42 -05:00
GenerateCopyPasteActions ( NameRow , GetName ( ) . ToString ( ) ) ;
2022-03-01 16:31:55 -05:00
static const FText MemberDisplayNameText = LOCTEXT ( " GraphMember_DisplayNameProperty " , " Display Name " ) ;
static const FText MemberDisplayNameToolTipFormat = LOCTEXT ( " GraphMember_DisplayNameDescriptionFormat " , " Optional, localized name used within the MetaSounds editor(s) to describe the given {0}. " ) ;
const FText MemberDisplayNameTooltipText = FText : : Format ( MemberDisplayNameToolTipFormat , GraphMember - > GetGraphMemberLabel ( ) ) ;
2024-02-01 19:54:42 -05:00
TSharedRef < FGraphMemberEditableTextDisplayName > DisplayNameValueText = MakeShared < FGraphMemberEditableTextDisplayName > ( GraphMember , MemberDisplayNameTooltipText ) ;
FDetailWidgetRow & DisplayNameRow = CategoryBuilder . AddCustomRow ( MemberDisplayNameText )
. EditCondition ( ! bIsReadOnly , nullptr )
2022-03-01 16:31:55 -05:00
. NameContent ( )
[
SNew ( STextBlock )
. Font ( IDetailLayoutBuilder : : GetDetailFontBold ( ) )
. Text ( MemberDisplayNameText )
. ToolTipText ( MemberDisplayNameTooltipText )
]
. ValueContent ( )
[
2024-02-01 19:54:42 -05:00
SNew ( STextPropertyEditableTextBox , DisplayNameValueText )
2022-03-01 16:31:55 -05:00
. WrapTextAt ( 500 )
. MinDesiredWidth ( 25.0f )
. MaxDesiredHeight ( 200 )
] ;
2024-02-01 19:54:42 -05:00
GenerateCopyPasteActions ( DisplayNameRow , DisplayNameValueText - > GetText ( 0 ) . ToString ( ) ) ;
2022-03-01 16:31:55 -05:00
static const FText MemberDescriptionText = LOCTEXT ( " Member_DescriptionPropertyName " , " Description " ) ;
static const FText MemberDescriptionToolTipFormat = LOCTEXT ( " Member_DescriptionToolTipFormat " , " Description for {0}. For example, used as a tooltip when displayed on another graph's referencing node. " ) ;
const FText MemberDescriptionToolTipText = FText : : Format ( MemberDescriptionToolTipFormat , GraphMember - > GetGraphMemberLabel ( ) ) ;
2024-02-01 19:54:42 -05:00
TSharedRef < FGraphMemberEditableTextDescription > DescriptionValueText = MakeShared < FGraphMemberEditableTextDescription > ( GraphMember , MemberDescriptionToolTipText ) ;
FDetailWidgetRow & DescriptionRow = CategoryBuilder . AddCustomRow ( MemberDescriptionText )
. IsEnabled ( true )
. EditCondition ( ! bIsReadOnly , nullptr )
2022-03-01 16:31:55 -05:00
. NameContent ( )
[
SNew ( STextBlock )
. Font ( IDetailLayoutBuilder : : GetDetailFontBold ( ) )
. Text ( MemberDescriptionText )
. ToolTipText ( MemberDescriptionToolTipText )
]
. ValueContent ( )
[
2024-02-01 19:54:42 -05:00
SNew ( STextPropertyEditableTextBox , DescriptionValueText )
2022-03-01 16:31:55 -05:00
. WrapTextAt ( 500 )
. MinDesiredWidth ( 25.0f )
. MaxDesiredHeight ( 200 )
] ;
2024-02-01 19:54:42 -05:00
GenerateCopyPasteActions ( DescriptionRow , DescriptionValueText - > GetText ( 0 ) . ToString ( ) ) ;
2022-03-01 16:31:55 -05:00
2024-02-01 19:54:42 -05:00
DataTypeSelector . AddDataTypeSelector ( InDetailLayout , MemberCustomizationStyle : : DataTypeNameText , GraphMember , ! bIsReadOnly ) ;
2022-03-01 16:31:55 -05:00
}
void FMetasoundMemberDetailCustomization : : CustomizeDetails ( IDetailLayoutBuilder & InDetailLayout )
{
CacheMemberData ( InDetailLayout ) ;
if ( GraphMember . IsValid ( ) )
{
CustomizeGeneralCategory ( InDetailLayout ) ;
CustomizeDefaultCategory ( InDetailLayout ) ;
}
}
void FMetasoundMemberDetailCustomization : : OnNameChanged ( const FText & InNewName )
{
using namespace Frontend ;
bIsNameInvalid = false ;
NameEditableTextBox - > SetError ( FText : : GetEmpty ( ) ) ;
if ( ! ensure ( GraphMember . IsValid ( ) ) )
{
return ;
}
FText Error ;
if ( ! GraphMember - > CanRename ( InNewName , Error ) )
{
bIsNameInvalid = true ;
NameEditableTextBox - > SetError ( Error ) ;
}
}
FText FMetasoundMemberDetailCustomization : : GetName ( ) const
{
if ( GraphMember . IsValid ( ) )
{
return FText : : FromName ( GraphMember - > GetMemberName ( ) ) ;
}
return FText : : GetEmpty ( ) ;
}
2022-03-04 03:48:32 -05:00
Frontend : : FDocumentHandle FMetasoundMemberDetailCustomization : : GetDocumentHandle ( ) const
{
if ( GraphMember . IsValid ( ) )
{
if ( UMetasoundEditorGraph * Graph = GraphMember - > GetOwningGraph ( ) )
{
return Graph - > GetDocumentHandle ( ) ;
}
}
return Frontend : : IDocumentController : : GetInvalidHandle ( ) ;
}
2022-03-01 16:31:55 -05:00
bool FMetasoundMemberDetailCustomization : : IsGraphEditable ( ) const
{
if ( GraphMember . IsValid ( ) )
{
if ( const UMetasoundEditorGraph * OwningGraph = GraphMember - > GetOwningGraph ( ) )
{
return OwningGraph - > IsEditable ( ) ;
}
}
return false ;
}
FText FMetasoundMemberDetailCustomization : : GetDisplayName ( ) const
{
using namespace Frontend ;
if ( GraphMember . IsValid ( ) )
{
return GraphMember - > GetDisplayName ( ) ;
}
return FText : : GetEmpty ( ) ;
}
void FMetasoundMemberDetailCustomization : : OnTooltipCommitted ( const FText & InNewText , ETextCommit : : Type InTextCommit )
{
using namespace Frontend ;
if ( GraphMember . IsValid ( ) )
{
constexpr bool bPostTransaction = true ;
GraphMember - > SetDescription ( InNewText , bPostTransaction ) ;
}
}
FText FMetasoundMemberDetailCustomization : : GetTooltip ( ) const
{
if ( GraphMember . IsValid ( ) )
{
return GraphMember - > GetDescription ( ) ;
}
return FText : : GetEmpty ( ) ;
}
2022-03-04 03:48:32 -05:00
EVisibility FMetasoundVertexDetailCustomization : : GetDefaultVisibility ( ) const
{
using namespace Frontend ;
if ( GraphMember . IsValid ( ) )
{
bool bIsInputConnected = false ;
FConstNodeHandle NodeHandle = CastChecked < UMetasoundEditorGraphVertex > ( GraphMember ) - > GetConstNodeHandle ( ) ;
if ( NodeHandle - > IsValid ( ) )
{
NodeHandle - > IterateConstInputs ( [ & bIsInputConnected ] ( FConstInputHandle InputHandle )
{
bIsInputConnected | = InputHandle - > IsConnectionUserModifiable ( ) & & InputHandle - > IsConnected ( ) ;
} ) ;
}
return bIsInputConnected ? EVisibility : : Collapsed : EVisibility : : Visible ;
}
return EVisibility : : Collapsed ;
}
2022-03-01 16:31:55 -05:00
void FMetasoundMemberDetailCustomization : : OnNameCommitted ( const FText & InNewName , ETextCommit : : Type InTextCommit )
{
using namespace Frontend ;
if ( ! bIsNameInvalid & & GraphMember . IsValid ( ) )
{
const FText TransactionLabel = FText : : Format ( LOCTEXT ( " RenameGraphMember_Format " , " Set MetaSound {0}'s Name " ) , GraphMember - > GetGraphMemberLabel ( ) ) ;
const FScopedTransaction Transaction ( TransactionLabel ) ;
constexpr bool bPostTransaction = false ;
GraphMember - > SetDisplayName ( FText : : GetEmpty ( ) , bPostTransaction ) ;
GraphMember - > SetMemberName ( * InNewName . ToString ( ) , bPostTransaction ) ;
}
NameEditableTextBox - > SetError ( FText : : GetEmpty ( ) ) ;
bIsNameInvalid = false ;
}
2022-07-18 17:14:25 -04:00
void FMetasoundVertexDetailCustomization : : AddConstructorPinRow ( IDetailLayoutBuilder & InDetailLayout )
{
if ( UMetasoundEditorGraphVertex * Vertex = Cast < UMetasoundEditorGraphVertex > ( GraphMember . Get ( ) ) )
{
InDetailLayout . EditCategory ( " General " ) . AddCustomRow ( MemberCustomizationPrivate : : ConstructorPinText )
. IsEnabled ( IsGraphEditable ( ) & & ! IsInterfaceMember ( ) )
. NameContent ( )
[
SNew ( STextBlock )
. Text ( MemberCustomizationPrivate : : ConstructorPinText )
. ToolTipText ( MemberCustomizationPrivate : : ConstructorPinTooltip )
. Font ( IDetailLayoutBuilder : : GetDetailFontBold ( ) )
]
. ValueContent ( )
[
SAssignNew ( ConstructorPinCheckbox , SCheckBox )
. IsChecked_Lambda ( [ this , Vertex ] ( )
{
return OnGetConstructorPinCheckboxState ( Vertex ) ;
} )
. OnCheckStateChanged_Lambda ( [ this , Vertex ] ( ECheckBoxState InNewState )
{
OnConstructorPinStateChanged ( Vertex , InNewState ) ;
} )
[
SNew ( STextBlock )
. Font ( IDetailLayoutBuilder : : GetDetailFont ( ) )
]
] ;
}
}
2022-03-01 16:31:55 -05:00
void FMetasoundVertexDetailCustomization : : CustomizeGeneralCategory ( IDetailLayoutBuilder & InDetailLayout )
{
FMetasoundMemberDetailCustomization : : CustomizeGeneralCategory ( InDetailLayout ) ;
UMetasoundEditorGraphVertex * Vertex = Cast < UMetasoundEditorGraphVertex > ( GraphMember . Get ( ) ) ;
2022-07-18 17:14:25 -04:00
if ( ! ensure ( Vertex ) )
2022-03-01 16:31:55 -05:00
{
2022-07-18 17:14:25 -04:00
return ;
2022-03-01 16:31:55 -05:00
}
2022-07-18 17:14:25 -04:00
// Constructor pin
2022-08-19 11:39:24 -04:00
Frontend : : FDataTypeRegistryInfo DataTypeInfo ;
Frontend : : IDataTypeRegistry : : Get ( ) . GetDataTypeInfo ( Vertex - > GetDataType ( ) , DataTypeInfo ) ;
if ( DataTypeInfo . bIsConstructorType )
2022-07-18 17:14:25 -04:00
{
2022-08-19 11:39:24 -04:00
AddConstructorPinRow ( InDetailLayout ) ;
2022-07-18 17:14:25 -04:00
}
// Sort order
IDetailCategoryBuilder & CategoryBuilder = FMetasoundMemberDetailCustomization : : GetGeneralCategoryBuilder ( InDetailLayout ) ;
TWeakObjectPtr < UMetasoundEditorGraphVertex > VertexPtr = Vertex ;
static const FText SortOrderText = LOCTEXT ( " Vertex_SortOrderPropertyName " , " Sort Order " ) ;
static const FText SortOrderToolTipFormat = LOCTEXT ( " Vertex_SortOrderToolTipFormat " , " Sort Order for {0}. Used to organize pins in node view. The higher the number, the lower in the list. " ) ;
const FText SortOrderToolTipText = FText : : Format ( SortOrderToolTipFormat , GraphMember - > GetGraphMemberLabel ( ) ) ;
CategoryBuilder . AddCustomRow ( SortOrderText )
. EditCondition ( IsGraphEditable ( ) , nullptr )
. NameContent ( )
[
SNew ( STextBlock )
. Font ( IDetailLayoutBuilder : : GetDetailFontBold ( ) )
. Text ( SortOrderText )
. ToolTipText ( SortOrderToolTipText )
]
. ValueContent ( )
[
SNew ( SNumericEntryBox < int32 > )
. Value_Lambda ( [ VertexPtr ] ( ) { return VertexPtr - > GetSortOrderIndex ( ) ; } )
. AllowSpin ( false )
. UndeterminedString ( LOCTEXT ( " Vertex_SortOrder_MultipleValues " , " Multiple " ) )
. OnValueCommitted_Lambda ( [ VertexPtr ] ( int32 NewValue , ETextCommit : : Type CommitInfo )
{
if ( ! VertexPtr . IsValid ( ) )
{
return ;
}
const FText TransactionTitle = FText : : Format ( LOCTEXT ( " SetVertexSortOrderFormat " , " Set MetaSound Graph {0} '{1}' SortOrder to {2} " ) ,
VertexPtr - > GetGraphMemberLabel ( ) ,
VertexPtr - > GetDisplayName ( ) ,
FText : : AsNumber ( NewValue ) ) ;
FScopedTransaction Transaction ( TransactionTitle ) ;
UObject * MetaSoundObject = VertexPtr - > GetOutermostObject ( ) ;
FMetasoundAssetBase * MetaSoundAsset = Metasound : : IMetasoundUObjectRegistry : : Get ( ) . GetObjectAsAssetBase ( MetaSoundObject ) ;
check ( MetaSoundAsset ) ;
MetaSoundObject - > Modify ( ) ;
MetaSoundAsset - > GetGraphChecked ( ) . Modify ( ) ;
VertexPtr - > Modify ( ) ;
VertexPtr - > SetSortOrderIndex ( NewValue ) ;
constexpr bool bInForceViewSynchronization = true ;
FGraphBuilder : : RegisterGraphWithFrontend ( * MetaSoundObject , bInForceViewSynchronization ) ;
} )
. Font ( IDetailLayoutBuilder : : GetDetailFont ( ) )
] ;
2022-03-01 16:31:55 -05:00
}
2021-12-13 18:15:01 -05:00
2022-03-04 03:48:32 -05:00
bool FMetasoundVertexDetailCustomization : : IsInterfaceMember ( ) const
2022-02-09 12:52:07 -05:00
{
2022-03-01 16:31:55 -05:00
if ( GraphMember . IsValid ( ) )
2022-02-09 12:52:07 -05:00
{
2022-03-04 03:48:32 -05:00
return CastChecked < UMetasoundEditorGraphVertex > ( GraphMember ) - > IsInterfaceMember ( ) ;
2022-02-09 12:52:07 -05:00
}
2022-03-04 03:48:32 -05:00
return false ;
2022-02-09 12:52:07 -05:00
}
bool FMetasoundInputDetailCustomization : : GetInputInheritsDefault ( ) const
{
2022-03-01 16:31:55 -05:00
if ( UMetasoundEditorGraphInput * Input = Cast < UMetasoundEditorGraphInput > ( GraphMember . Get ( ) ) )
2022-02-09 12:52:07 -05:00
{
const TSet < FName > & InputsInheritingDefault = GetDocumentHandle ( ) - > GetRootGraph ( ) - > GetInputsInheritingDefault ( ) ;
2022-03-01 16:31:55 -05:00
FName NodeName = Input - > GetConstNodeHandle ( ) - > GetNodeName ( ) ;
2022-02-09 12:52:07 -05:00
return InputsInheritingDefault . Contains ( NodeName ) ;
}
return false ;
}
void FMetasoundInputDetailCustomization : : SetInputInheritsDefault ( )
{
2022-03-01 16:31:55 -05:00
if ( UMetasoundEditorGraphInput * Input = Cast < UMetasoundEditorGraphInput > ( GraphMember . Get ( ) ) )
2022-02-09 12:52:07 -05:00
{
2022-03-01 16:31:55 -05:00
if ( UMetasoundEditorGraphMemberDefaultLiteral * MemberDefaultLiteral = Input - > GetLiteral ( ) )
2022-02-09 12:52:07 -05:00
{
2022-03-01 16:31:55 -05:00
FScopedTransaction Transaction ( LOCTEXT ( " SetPresetInputOverrideTransaction " , " Set MetaSound Preset Input Overridden " ) ) ;
Input - > GetOutermost ( ) - > Modify ( ) ;
Input - > Modify ( ) ;
MemberDefaultLiteral - > Modify ( ) ;
constexpr bool bDefaultIsInherited = true ;
const FName NodeName = Input - > GetConstNodeHandle ( ) - > GetNodeName ( ) ;
GetDocumentHandle ( ) - > GetRootGraph ( ) - > SetInputInheritsDefault ( NodeName , bDefaultIsInherited ) ;
if ( UObject * Metasound = Input - > GetOutermostObject ( ) )
{
FGraphBuilder : : RegisterGraphWithFrontend ( * Metasound ) ;
}
2022-02-09 12:52:07 -05:00
}
}
}
void FMetasoundInputDetailCustomization : : ClearInputInheritsDefault ( )
{
2022-03-01 16:31:55 -05:00
if ( UMetasoundEditorGraphInput * Input = Cast < UMetasoundEditorGraphInput > ( GraphMember . Get ( ) ) )
2022-02-09 12:52:07 -05:00
{
2022-03-01 16:31:55 -05:00
if ( UMetasoundEditorGraphMemberDefaultLiteral * MemberDefaultLiteral = Input - > GetLiteral ( ) )
2022-02-09 12:52:07 -05:00
{
2022-03-01 16:31:55 -05:00
FScopedTransaction Transaction ( LOCTEXT ( " ClearPresetInputOverrideTransaction " , " Clear MetaSound Preset Input Overridden " ) ) ;
2022-02-09 12:52:07 -05:00
2022-03-01 16:31:55 -05:00
Input - > GetOutermost ( ) - > Modify ( ) ;
Input - > Modify ( ) ;
MemberDefaultLiteral - > Modify ( ) ;
constexpr bool bDefaultIsInherited = false ;
const FName NodeName = Input - > GetConstNodeHandle ( ) - > GetNodeName ( ) ;
GetDocumentHandle ( ) - > GetRootGraph ( ) - > SetInputInheritsDefault ( NodeName , bDefaultIsInherited ) ;
Input - > UpdateFrontendDefaultLiteral ( false /* bPostTransaction */ ) ;
if ( UMetasoundEditorGraphMemberDefaultLiteral * Literal = Input - > GetLiteral ( ) )
{
Literal - > ForceRefresh ( ) ;
}
if ( UObject * Metasound = Input - > GetOutermostObject ( ) )
{
FGraphBuilder : : RegisterGraphWithFrontend ( * Metasound ) ;
}
2022-02-09 12:52:07 -05:00
}
}
}
2022-07-14 17:51:07 -04:00
2022-07-18 17:14:25 -04:00
ECheckBoxState FMetasoundVertexDetailCustomization : : OnGetConstructorPinCheckboxState ( TWeakObjectPtr < UMetasoundEditorGraphVertex > InGraphVertex ) const
2022-04-25 13:29:29 -04:00
{
2022-07-18 17:14:25 -04:00
if ( InGraphVertex . IsValid ( ) )
2022-04-25 13:29:29 -04:00
{
2022-07-18 17:14:25 -04:00
return InGraphVertex - > GetVertexAccessType ( ) = = EMetasoundFrontendVertexAccessType : : Value ? ECheckBoxState : : Checked : ECheckBoxState : : Unchecked ;
}
return ECheckBoxState : : Undetermined ;
}
void FMetasoundVertexDetailCustomization : : OnConstructorPinStateChanged ( TWeakObjectPtr < UMetasoundEditorGraphVertex > InGraphVertex , ECheckBoxState InNewState )
{
if ( InGraphVertex . IsValid ( ) & & ConstructorPinCheckbox . IsValid ( ) )
{
EMetasoundFrontendVertexAccessType NewAccessType = InNewState = = ECheckBoxState : : Checked ?
EMetasoundFrontendVertexAccessType : : Value : EMetasoundFrontendVertexAccessType : : Reference ;
if ( InGraphVertex - > GetVertexAccessType ( ) = = NewAccessType )
{
return ;
}
// Have to stop playback to avoid attempting to change live edit data on invalid input type.
check ( GEditor ) ;
GEditor - > ResetPreviewAudioComponent ( ) ;
InGraphVertex - > SetVertexAccessType ( NewAccessType ) ;
if ( FMetasoundAssetBase * MetasoundAsset = Metasound : : IMetasoundUObjectRegistry : : Get ( ) . GetObjectAsAssetBase ( GraphMember - > GetOutermostObject ( ) ) )
{
2022-09-22 15:02:24 -04:00
MetasoundAsset - > GetModifyContext ( ) . AddMemberIDsModified ( { GraphMember - > GetMemberID ( ) } ) ;
2022-07-18 17:14:25 -04:00
}
2022-04-25 13:29:29 -04:00
}
}
2022-02-09 12:52:07 -05:00
void FMetasoundInputDetailCustomization : : CustomizeDetails ( IDetailLayoutBuilder & InDetailLayout )
{
CacheMemberData ( InDetailLayout ) ;
if ( ! GraphMember . IsValid ( ) )
{
return ;
}
CustomizeGeneralCategory ( InDetailLayout ) ;
2022-03-01 16:31:55 -05:00
UMetasoundEditorGraphMemberDefaultLiteral * MemberDefaultLiteral = GraphMember - > GetLiteral ( ) ;
if ( ! MemberDefaultLiteral )
2022-02-09 12:52:07 -05:00
{
return ;
}
// Build preset row first if graph has managed interface, not default constructed, & not a trigger
const bool bIsPreset = GetDocumentHandle ( ) - > GetRootGraphClass ( ) . PresetOptions . bIsPreset ;
const bool bIsDefaultConstructed = MemberDefaultLiteral - > GetLiteralType ( ) = = EMetasoundFrontendLiteralType : : None ;
const bool bIsTriggerDataType = GraphMember - > GetDataType ( ) = = GetMetasoundDataTypeName < FTrigger > ( ) ;
if ( bIsPreset & & ! bIsDefaultConstructed & & ! bIsTriggerDataType )
{
GetDefaultCategoryBuilder ( InDetailLayout )
. AddCustomRow ( MemberCustomizationPrivate : : OverrideInputDefaultText )
. NameContent ( )
[
SNew ( STextBlock )
. Text ( MemberCustomizationPrivate : : OverrideInputDefaultText )
. Font ( IDetailLayoutBuilder : : GetDetailFontBold ( ) )
. ToolTipText ( MemberCustomizationPrivate : : OverrideInputDefaultTooltip )
]
. ValueContent ( )
[
SNew ( SCheckBox )
. OnCheckStateChanged_Lambda ( [ this ] ( ECheckBoxState State )
{
switch ( State )
{
case ECheckBoxState : : Checked :
{
ClearInputInheritsDefault ( ) ;
break ;
}
case ECheckBoxState : : Unchecked :
case ECheckBoxState : : Undetermined :
default :
{
SetInputInheritsDefault ( ) ;
}
}
} )
. IsChecked_Lambda ( [ this ] ( ) { return GetInputInheritsDefault ( ) ? ECheckBoxState : : Unchecked : ECheckBoxState : : Checked ; } )
. ToolTipText ( MemberCustomizationPrivate : : OverrideInputDefaultTooltip )
] ;
}
TArray < IDetailPropertyRow * > DefaultPropertyRows = CustomizeDefaultCategory ( InDetailLayout ) ;
if ( bIsPreset & & ! bIsDefaultConstructed & & ! bIsTriggerDataType )
{
const UMetasoundEditorGraphInput * Input = Cast < UMetasoundEditorGraphInput > ( MemberDefaultLiteral - > GetParentMember ( ) ) ;
if ( ensure ( Input ) )
{
auto PropertyEnabled = TAttribute < bool > : : CreateLambda ( [ this ] { return ! GetInputInheritsDefault ( ) ; } ) ;
for ( IDetailPropertyRow * DefaultPropertyRow : DefaultPropertyRows )
{
DefaultPropertyRow - > EditCondition ( PropertyEnabled , { } ) ;
FResetToDefaultOverride ResetOverride = FResetToDefaultOverride : : Create (
FIsResetToDefaultVisible : : CreateLambda ( [ this ] ( TSharedPtr < IPropertyHandle > /* PropertyHandle */ ) { return ! GetInputInheritsDefault ( ) ; } ) ,
FResetToDefaultHandler : : CreateLambda ( [ this ] ( TSharedPtr < IPropertyHandle > /* PropertyHandle */ ) { SetInputInheritsDefault ( ) ; } ) ) ;
DefaultPropertyRow - > OverrideResetToDefault ( ResetOverride ) ;
}
}
2022-07-18 17:14:25 -04:00
}
else if ( ! bIsPreset )
{
// Make default value uneditable while playing for constructor inputs
const UMetasoundEditorGraphInput * Input = Cast < UMetasoundEditorGraphInput > ( MemberDefaultLiteral - > GetParentMember ( ) ) ;
if ( ensure ( Input ) )
{
auto PropertyEnabled = TAttribute < bool > : : CreateLambda ( [ this , Input ]
{
if ( Input - > GetVertexAccessType ( ) = = EMetasoundFrontendVertexAccessType : : Value )
{
UObject * MetaSoundObject = Input - > GetOutermostObject ( ) ;
if ( TSharedPtr < FEditor > MetaSoundEditor = FGraphBuilder : : GetEditorForMetasound ( * MetaSoundObject ) )
{
return ! MetaSoundEditor - > IsPlaying ( ) ;
}
}
return true ;
} ) ;
for ( IDetailPropertyRow * DefaultPropertyRow : DefaultPropertyRows )
{
DefaultPropertyRow - > EditCondition ( PropertyEnabled , { } ) ;
}
}
2022-02-09 12:52:07 -05:00
}
}
bool FMetasoundInputDetailCustomization : : IsDefaultEditable ( ) const
{
return ! GetInputInheritsDefault ( ) ;
}
2022-03-04 03:48:32 -05:00
EVisibility FMetasoundVariableDetailCustomization : : GetDefaultVisibility ( ) const
2021-12-13 18:15:01 -05:00
{
2022-03-04 03:48:32 -05:00
using namespace Frontend ;
2021-12-13 18:15:01 -05:00
if ( GraphMember . IsValid ( ) )
{
2022-03-04 03:48:32 -05:00
bool bIsInputConnected = false ;
const UMetasoundEditorGraphVariable * Variable = CastChecked < UMetasoundEditorGraphVariable > ( GraphMember ) ;
FConstNodeHandle NodeHandle = Variable - > GetConstVariableHandle ( ) - > FindMutatorNode ( ) ;
if ( NodeHandle - > IsValid ( ) )
{
NodeHandle - > IterateConstInputs ( [ & bIsInputConnected ] ( FConstInputHandle InputHandle )
{
bIsInputConnected | = InputHandle - > IsConnectionUserModifiable ( ) & & InputHandle - > IsConnected ( ) ;
} ) ;
}
return bIsInputConnected ? EVisibility : : Collapsed : EVisibility : : Visible ;
2021-12-13 18:15:01 -05:00
}
2022-03-04 03:48:32 -05:00
return EVisibility : : Collapsed ;
2021-12-13 18:15:01 -05:00
}
2021-03-19 15:10:57 -04:00
} // namespace Editor
} // namespace Metasound
# undef LOCTEXT_NAMESPACE