// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "Components/Widget.h" #include "CoreMinimal.h" #include "DetailLayoutBuilder.h" #include "IDetailCustomization.h" #include "IPropertyTypeCustomization.h" #include "Layout/Visibility.h" #include "MetasoundAssetBase.h" #include "MetasoundEditorGraphNode.h" #include "MetasoundEditorGraphInputNodes.h" #include "MetasoundUObjectRegistry.h" #include "ScopedTransaction.h" #include "Types/SlateEnums.h" #include "UObject/NameTypes.h" #include "Widgets/Input/SEditableTextBox.h" #include "WorkflowOrientedApp/SModeWidget.h" // Forward Declarations class FDetailWidgetRow; class FPropertyRestriction; class IDetailLayoutBuilder; class IPropertyHandle; class SCheckBox; class STextComboBox; #define LOCTEXT_NAMESPACE "MetaSoundEditor" namespace Metasound { namespace Editor { class FMetasoundInputArrayDetailCustomizationBase : public IPropertyTypeCustomization { public: //~ Begin IPropertyTypeCustomization virtual void CustomizeHeader(TSharedRef StructPropertyHandle, FDetailWidgetRow& HeaderRow, IPropertyTypeCustomizationUtils& StructCustomizationUtils) override; virtual void CustomizeChildren(TSharedRef StructPropertyHandle, IDetailChildrenBuilder& ChildBuilder, IPropertyTypeCustomizationUtils& StructCustomizationUtils) override; //~ End IPropertyTypeCustomization protected: virtual FText GetPropertyNameOverride() const { return FText::GetEmpty(); } virtual TSharedRef CreateStructureWidget(TSharedPtr& PropertyHandle) const = 0; virtual void CacheProxyData(TSharedPtr ProxyHandle) { } private: TSharedRef CreateNameWidget(TSharedPtr StructPropertyHandle) const; TSharedRef CreateValueWidget(TSharedPtr ParentArrayProperty, TSharedPtr StructPropertyHandle, bool bIsInArray) const; }; class FMetasoundInputBoolDetailCustomization : public FMetasoundInputArrayDetailCustomizationBase { protected: virtual FText GetPropertyNameOverride() const override; virtual TSharedRef CreateStructureWidget(TSharedPtr& StructPropertyHandle) const override; virtual void CacheProxyData(TSharedPtr ProxyHandle) override; private: FName DataTypeName; }; class FMetasoundInputIntDetailCustomization : public FMetasoundInputArrayDetailCustomizationBase { protected: virtual TSharedRef CreateStructureWidget(TSharedPtr& StructPropertyHandle) const override; virtual void CacheProxyData(TSharedPtr ProxyHandle) override; private: FName DataTypeName; }; class FMetasoundInputObjectDetailCustomization : public FMetasoundInputArrayDetailCustomizationBase { protected: virtual TSharedRef CreateStructureWidget(TSharedPtr& StructPropertyHandle) const override; virtual void CacheProxyData(TSharedPtr ProxyHandle) override; private: TWeakObjectPtr ProxyGenClass; }; class FMetasoundVariableDataTypeSelector { public: void AddDataTypeSelector(IDetailLayoutBuilder& InDetailLayoutBuilder, const FText& InRowName, TWeakObjectPtr InGraphVariable, bool bIsRequired); void OnDataTypeArrayChanged(TWeakObjectPtr InGraphVariable, ECheckBoxState InNewState); ECheckBoxState OnGetDataTypeArrayCheckState(TWeakObjectPtr InGraphVariable) const; void OnBaseDataTypeChanged(TWeakObjectPtr InGraphVariable, TSharedPtr ItemSelected, ESelectInfo::Type SelectInfo); protected: TFunction OnDataTypeChanged; private: TSharedPtr DataTypeArrayCheckbox; TSharedPtr DataTypeComboBox; TArray> DataTypeNames; IDetailLayoutBuilder* DetailLayoutBuilder = nullptr; }; template class TMetasoundVariableDetailCustomization : public IDetailCustomization, public FMetasoundVariableDataTypeSelector { public: TMetasoundVariableDetailCustomization(const FText& InVariableLabel) : IDetailCustomization() , VariableLabel(InVariableLabel) { } protected: FText VariableLabel; TWeakObjectPtr GraphVariable; TSharedPtr DisplayNameEditableTextBox; bool bIsNameInvalid = false; // IDetailCustomization interface virtual void CustomizeDetails(IDetailLayoutBuilder& DetailLayout) override { TArray> Objects; DetailLayout.GetObjectsBeingCustomized(Objects); if (Objects.IsEmpty()) { return; } GraphVariable = Cast(Objects[0].Get()); } // End of IDetailCustomization interface virtual void OnDisplayNameChanged(const FText& InNewText) = 0; FText GetDisplayName() const { using namespace Frontend; if (GraphVariable.IsValid()) { return GraphVariable->GetNodeHandle()->GetDisplayName(); } return FText::GetEmpty(); } bool IsRequired() const { if (GraphVariable.IsValid()) { Frontend::FConstNodeHandle NodeHandle = GraphVariable->GetConstNodeHandle(); return NodeHandle->IsRequired(); } return true; } void OnTooltipCommitted(const FText& InNewText, ETextCommit::Type InTextCommit) { using namespace Frontend; if (GraphVariable.IsValid()) { const FText TransactionLabel = FText::Format(LOCTEXT("SetTooltip", "Set the MetaSound {0}'s tooltip"), VariableLabel); const FScopedTransaction Transaction(TransactionLabel); FNodeHandle NodeHandle = GraphVariable->GetNodeHandle(); NodeHandle->SetDescription(InNewText); } } FText GetTooltip() const { using namespace Frontend; if (GraphVariable.IsValid()) { FNodeHandle NodeHandle = GraphVariable->GetNodeHandle(); return NodeHandle->GetDescription(); } return FText::GetEmpty(); } void OnDisplayNameCommitted(const FText& InNewName, ETextCommit::Type InTextCommit) { using namespace Frontend; if (!bIsNameInvalid && GraphVariable.IsValid()) { const FText TransactionLabel = FText::Format(LOCTEXT("Rename Variable", "Rename Metasound {0}"), VariableLabel); const FScopedTransaction Transaction(TransactionLabel); FNodeHandle NodeHandle = GraphVariable->GetNodeHandle(); NodeHandle->SetDisplayName(InNewName); GraphVariable->NameChanged.Broadcast(NodeHandle->GetID()); DisplayNameEditableTextBox->SetError(FText::GetEmpty()); } } ECheckBoxState OnGetPrivateCheckboxState() const { if (GraphVariable.IsValid()) { return GraphVariable->GetNodeHandle()->GetNodeStyle().bIsPrivate ? ECheckBoxState::Checked : ECheckBoxState::Unchecked; } return ECheckBoxState::Unchecked; } void OnPrivateChanged(ECheckBoxState InNewState) { if (GraphVariable.IsValid()) { const bool bIsChecked = InNewState == ECheckBoxState::Checked; Frontend::FNodeHandle NodeHandle = GraphVariable->GetNodeHandle(); FMetasoundFrontendNodeStyle NodeStyle = NodeHandle->GetNodeStyle(); NodeStyle.bIsPrivate = bIsChecked; NodeHandle->SetNodeStyle(NodeStyle); } } EVisibility ExposePrivateVisibility() const { if (IsRequired()) { return EVisibility::Collapsed; } return EVisibility::Visible; } }; class FMetasoundInputDetailCustomization : public TMetasoundVariableDetailCustomization { public: FMetasoundInputDetailCustomization() : TMetasoundVariableDetailCustomization(LOCTEXT("InputVariableLabel", "Input")) { } // IDetailCustomization interface virtual void CustomizeDetails(IDetailLayoutBuilder& DetailLayout) override; // End of IDetailCustomization interface protected: virtual void OnDisplayNameChanged(const FText& InNewText) override; private: void SetDefaultPropertyMetaData(TSharedRef InDefaultPropertyHandle) const; FName GetLiteralDataType() const; }; class FMetasoundOutputDetailCustomization : public TMetasoundVariableDetailCustomization { public: FMetasoundOutputDetailCustomization() : TMetasoundVariableDetailCustomization(LOCTEXT("OutputVariableLabel", "Output")) { } // IDetailCustomization interface virtual void CustomizeDetails(IDetailLayoutBuilder& DetailLayout) override; // End of IDetailCustomization interface protected: virtual void OnDisplayNameChanged(const FText& InNewText) override; private: void SetDefaultPropertyMetaData(TSharedRef InDefaultPropertyHandle) const; FName GetLiteralDataType() const; }; } // namespace Editor } // namespace Metasound #undef LOCTEXT_NAMESPACE