// Copyright Epic Games, Inc. All Rights Reserved. #include "MetasoundExampleNodeDetailsCustomization.h" #include "DetailWidgetRow.h" #include "IDetailChildrenBuilder.h" #include "InstancedStructDetails.h" #include "MetasoundEditorGraphNode.h" #include "MetasoundBuilderBase.h" #include "MetasoundExampleNodeConfiguration.h" #include "MetasoundNodeConfigurationCustomization.h" #include "PropertyEditorModule.h" #include "Widgets/Input/SSlider.h" #define LOCTEXT_NAMESPACE "MetasoundExperimentalEditor" const FString StructIdentifierWithDelimiters = TEXT(".Struct."); FExampleWidgetNodeConfigurationCustomization::FExampleWidgetNodeConfigurationCustomization(TSharedPtr InStructProperty, TWeakObjectPtr InNode) : Metasound::Editor::FMetaSoundNodeConfigurationDataDetails(InStructProperty, InNode) { if (InStructProperty && InStructProperty->IsValidHandle()) { StructPropertyPath = InStructProperty->GeneratePathToProperty(); } } void FExampleWidgetNodeConfigurationCustomization::OnChildRowAdded(IDetailPropertyRow& ChildRow) { TSharedPtr ChildHandle = ChildRow.GetPropertyHandle(); if (!ChildHandle || !ChildHandle->IsValidHandle()) { return; } const FString PropertyPath = ChildHandle->GeneratePathToProperty(); // Customize a specific member if (PropertyPath == StructPropertyPath + StructIdentifierWithDelimiters + GET_MEMBER_NAME_CHECKED(FMetaSoundWidgetExampleNodeConfiguration, MyFloat).ToString()) { MyFloatPropertyHandle = ChildHandle; TSharedPtr NameWidget; TSharedPtr ValueWidget; FDetailWidgetRow Row; ChildRow.GetDefaultWidgets(NameWidget, ValueWidget, Row); ChildRow.CustomWidget(true) .NameContent() [ NameWidget.ToSharedRef() ] .ValueContent() [ SNew(SSlider) .MinValue(0.0f) .MaxValue(1.0f) .Value_Lambda([Handle=ChildRow.GetPropertyHandle()]{ float Value = 0.0f; if (Handle.IsValid() && Handle->IsValidHandle()) { Handle->GetValue(Value); } return Value; }) .OnValueChanged_Lambda([Handle = ChildRow.GetPropertyHandle()](float Value) { if (Handle.IsValid() && Handle->IsValidHandle()) { Handle->SetValue(Value); } }) ]; } // Add custom onvalue changed TDelegate OnValueChangedDelegate = TDelegate::CreateSP(this, &FExampleWidgetNodeConfigurationCustomization::OnChildPropertyChanged); ChildHandle->SetOnPropertyValueChangedWithData(OnValueChangedDelegate); // Add base class on value changed Metasound::Editor::FMetaSoundNodeConfigurationDataDetails::OnChildRowAdded(ChildRow); } void FExampleWidgetNodeConfigurationCustomization::OnChildPropertyChanged(const FPropertyChangedEvent& InPropertyChangedEvent) { if (InPropertyChangedEvent.GetPropertyName() == GET_MEMBER_NAME_CHECKED(FMetaSoundWidgetExampleNodeConfiguration, MyFloat)) { if (GraphNode.IsValid() && MyFloatPropertyHandle.IsValid() && MyFloatPropertyHandle->IsValidHandle()) { FMetaSoundFrontendDocumentBuilder& DocBuilder = GraphNode->GetBuilderChecked().GetBuilder(); const FGuid& NodeID = GraphNode->GetNodeID(); // Update the operator data value from the configuration property handle value // Node configuration operator data API is experimental // so this code will be made cleaner in the future TInstancedStruct Config = DocBuilder.FindNodeConfiguration(NodeID); TSharedPtr OperatorData = Config.Get().GetOperatorData(); const TSharedPtr WidgetOperatorData = StaticCastSharedPtr(OperatorData); TSharedPtr MutableWidgetOperatorData = ConstCastSharedPtr(WidgetOperatorData); MyFloatPropertyHandle->GetValue(MutableWidgetOperatorData->MyFloat); } } } #undef LOCTEXT_NAMESPACE