Files

3300 lines
144 KiB
C++

/*
* Copyright (c) <2017> Side Effects Software Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*/
#include "HoudiniParameterDetails.h"
#include "HoudiniApi.h"
#include "HoudiniAssetComponentDetails.h"
#include "HoudiniEngineEditorPrivatePCH.h"
#include "HoudiniAssetComponent.h"
#include "HoudiniAssetInput.h"
#include "HoudiniAssetInstanceInput.h"
#include "HoudiniAssetInstanceInputField.h"
#include "HoudiniAssetParameterButton.h"
#include "HoudiniAssetParameterChoice.h"
#include "HoudiniAssetParameterColor.h"
#include "HoudiniAssetParameterFile.h"
#include "HoudiniAssetParameterFolder.h"
#include "HoudiniAssetParameterFolderList.h"
#include "HoudiniAssetParameterFloat.h"
#include "HoudiniAssetParameterInt.h"
#include "HoudiniAssetParameterLabel.h"
#include "HoudiniAssetParameterMultiparm.h"
#include "HoudiniAssetParameterRamp.h"
#include "HoudiniAssetParameterSeparator.h"
#include "HoudiniAssetParameterString.h"
#include "HoudiniAssetParameterToggle.h"
#include "HoudiniRuntimeSettings.h"
#include "SNewFilePathPicker.h"
#include "Editor/CurveEditor/Public/CurveEditorSettings.h"
#include "DetailLayoutBuilder.h"
#include "Editor/SceneOutliner/Public/SceneOutlinerModule.h"
#include "Editor/SceneOutliner/Public/SceneOutlinerPublicTypes.h"
#include "Editor/UnrealEd/Public/AssetThumbnail.h"
#include "Editor/PropertyEditor/Public/PropertyCustomizationHelpers.h"
#include "Editor/PropertyEditor/Private/PropertyNode.h"
#include "Editor/PropertyEditor/Private/SDetailsViewBase.h"
#include "EditorDirectories.h"
#include "Engine/Selection.h"
#include "Engine/SkeletalMesh.h"
#include "Framework/MultiBox/MultiBoxBuilder.h"
#include "Internationalization/Internationalization.h"
#include "IDetailGroup.h"
#include "Particles/ParticleSystemComponent.h"
#include "SCurveEditor.h"
#include "SAssetDropTarget.h"
#include "Sound/SoundBase.h"
#include "Math/UnitConversion.h"
#include "Math/NumericLimits.h"
#include "Misc/Optional.h"
#include "Widgets/Colors/SColorPicker.h"
#include "Widgets/Colors/SColorBlock.h"
#include "Widgets/Input/NumericUnitTypeInterface.inl"
#include "Widgets/Input/SButton.h"
#include "Widgets/Input/SComboBox.h"
#include "Widgets/Input/SCheckBox.h"
#include "Widgets/Input/SEditableTextBox.h"
#include "Widgets/Input/SNumericEntryBox.h"
#include "Widgets/Input/SRotatorInputBox.h"
#include "Widgets/Input/SVectorInputBox.h"
#include "Widgets/Layout/SSeparator.h"
#include "Widgets/Layout/SUniformGridPanel.h"
#include "EngineUtils.h"
#define LOCTEXT_NAMESPACE HOUDINI_LOCTEXT_NAMESPACE
void
FHoudiniParameterDetails::CreateNameWidget( UHoudiniAssetParameter* InParam, FDetailWidgetRow & Row, bool WithLabel )
{
if ( !InParam || InParam->IsPendingKill() )
return;
FText ParameterLabelText = FText::FromString( InParam->GetParameterLabel() );
const FText & FinalParameterLabelText = WithLabel ? ParameterLabelText : FText::GetEmpty();
FText ParameterTooltip = GetParameterTooltip( InParam );
if ( InParam->bIsChildOfMultiparm && InParam->ParentParameter && !InParam->ParentParameter->IsPendingKill() )
{
TSharedRef< SHorizontalBox > HorizontalBox = SNew( SHorizontalBox );
// We have to make sure the ParentParameter is a multiparm, as folders will cause issues here
// ( we want to call RemoveMultiParmInstance or AddMultiParmInstance on the parent multiparm, not just the parent)
UHoudiniAssetParameter * ParentMultiparm = InParam->ParentParameter;
while ( ParentMultiparm && !ParentMultiparm->IsPendingKill() && !ParentMultiparm->bIsMultiparm )
ParentMultiparm = ParentMultiparm->ParentParameter;
// Failed to find the multiparm parent, better have the original parent than nullptr
if ( !ParentMultiparm || ParentMultiparm->IsPendingKill() )
ParentMultiparm = InParam->ParentParameter;
TSharedRef< SWidget > ClearButton = PropertyCustomizationHelpers::MakeClearButton(
FSimpleDelegate::CreateUObject(
(UHoudiniAssetParameterMultiparm *)ParentMultiparm,
&UHoudiniAssetParameterMultiparm::RemoveMultiparmInstance,
InParam->MultiparmInstanceIndex ),
LOCTEXT( "RemoveMultiparmInstanceToolTip", "Remove" ) );
TSharedRef< SWidget > AddButton = PropertyCustomizationHelpers::MakeAddButton(
FSimpleDelegate::CreateUObject(
(UHoudiniAssetParameterMultiparm *)ParentMultiparm,
&UHoudiniAssetParameterMultiparm::AddMultiparmInstance,
InParam->MultiparmInstanceIndex ),
LOCTEXT( "InsertBeforeMultiparmInstanceToolTip", "Insert Before" ) );
if ( InParam->ChildIndex != 0 )
{
AddButton.Get().SetVisibility( EVisibility::Hidden );
ClearButton.Get().SetVisibility( EVisibility::Hidden );
}
// Adding eventual padding for nested multiparams
UHoudiniAssetParameter* currentParentParameter = ParentMultiparm;
while ( currentParentParameter && currentParentParameter->bIsChildOfMultiparm )
{
if ( currentParentParameter->bIsMultiparm )
HorizontalBox->AddSlot().MaxWidth( 16.0f );
currentParentParameter = currentParentParameter->ParentParameter;
}
HorizontalBox->AddSlot().AutoWidth().Padding( 2.0f, 0.0f )
[
ClearButton
];
HorizontalBox->AddSlot().AutoWidth().Padding( 0.0f, 0.0f )
[
AddButton
];
HorizontalBox->AddSlot().Padding( 2, 5, 5, 2 )
[
SNew( STextBlock )
.Text( FinalParameterLabelText )
.ToolTipText( WithLabel ? ParameterTooltip : ParameterLabelText )
.Font( FEditorStyle::GetFontStyle( TEXT( "PropertyWindow.NormalFont" ) ) )
];
Row.NameWidget.Widget = HorizontalBox;
}
else
{
Row.NameWidget.Widget =
SNew( STextBlock )
.Text( FinalParameterLabelText )
.ToolTipText( ParameterTooltip )
.Font( FEditorStyle::GetFontStyle( TEXT( "PropertyWindow.NormalFont" ) ) );
}
}
FText
FHoudiniParameterDetails::GetParameterTooltip( UHoudiniAssetParameter* InParam )
{
if ( !InParam )
return FText();
/*
FString Tooltip = InParam->GetParameterLabel() + TEXT(" (") + InParam->GetParameterName() + TEXT(")");
if ( !InParam->GetParameterHelp().IsEmpty() )
Tooltip += TEXT ( ":\n") + InParam->GetParameterHelp();
return FText::FromString( Tooltip );
*/
if ( !InParam->GetParameterHelp().IsEmpty() )
return FText::FromString( InParam->GetParameterHelp() );
else
return FText::FromString( InParam->GetParameterLabel() + TEXT( " (" ) + InParam->GetParameterName() + TEXT( ")" ) );
}
void
FHoudiniParameterDetails::CreateWidget( IDetailCategoryBuilder & LocalDetailCategoryBuilder, UHoudiniAssetParameter* InParam )
{
if( !InParam || InParam->IsPendingKill() )
return;
if ( auto ParamFloat = Cast<UHoudiniAssetParameterFloat>( InParam ) )
{
CreateWidgetFloat( LocalDetailCategoryBuilder, *ParamFloat );
}
else if ( auto ParamFolder = Cast<UHoudiniAssetParameterFolder>( InParam ) )
{
CreateWidgetFolder( LocalDetailCategoryBuilder, *ParamFolder );
}
else if ( auto ParamFolderList = Cast<UHoudiniAssetParameterFolderList>( InParam ) )
{
CreateWidgetFolderList( LocalDetailCategoryBuilder, *ParamFolderList );
}
// Test Ramp before Multiparm!
else if ( auto ParamRamp = Cast<UHoudiniAssetParameterRamp>( InParam ) )
{
CreateWidgetRamp( LocalDetailCategoryBuilder, *ParamRamp );
}
else if ( auto ParamMultiparm = Cast<UHoudiniAssetParameterMultiparm>( InParam ) )
{
CreateWidgetMultiparm( LocalDetailCategoryBuilder, *ParamMultiparm );
}
else if ( auto ParamButton = Cast<UHoudiniAssetParameterButton>( InParam ) )
{
CreateWidgetButton( LocalDetailCategoryBuilder, *ParamButton );
}
else if ( auto ParamChoice = Cast<UHoudiniAssetParameterChoice>( InParam ) )
{
CreateWidgetChoice( LocalDetailCategoryBuilder, *ParamChoice );
}
else if ( auto ParamColor = Cast<UHoudiniAssetParameterColor>( InParam ) )
{
CreateWidgetColor( LocalDetailCategoryBuilder, *ParamColor );
}
else if ( auto ParamToggle = Cast<UHoudiniAssetParameterToggle>( InParam ) )
{
CreateWidgetToggle( LocalDetailCategoryBuilder, *ParamToggle );
}
else if ( auto ParamInput = Cast<UHoudiniAssetInput>( InParam ) )
{
CreateWidgetInput( LocalDetailCategoryBuilder, *ParamInput );
}
else if ( auto ParamInt = Cast<UHoudiniAssetParameterInt>( InParam ) )
{
CreateWidgetInt( LocalDetailCategoryBuilder, *ParamInt );
}
else if ( auto ParamInstanceInput = Cast<UHoudiniAssetInstanceInput>( InParam ) )
{
CreateWidgetInstanceInput( LocalDetailCategoryBuilder, *ParamInstanceInput );
}
else if ( auto ParamLabel = Cast<UHoudiniAssetParameterLabel>( InParam ) )
{
CreateWidgetLabel( LocalDetailCategoryBuilder, *ParamLabel );
}
else if ( auto ParamString = Cast<UHoudiniAssetParameterString>( InParam ) )
{
CreateWidgetString( LocalDetailCategoryBuilder, *ParamString );
}
else if ( auto ParamSeparator = Cast<UHoudiniAssetParameterSeparator>( InParam ) )
{
CreateWidgetSeparator( LocalDetailCategoryBuilder, *ParamSeparator );
}
else if ( auto ParamFile = Cast<UHoudiniAssetParameterFile>( InParam ) )
{
CreateWidgetFile( LocalDetailCategoryBuilder, *ParamFile );
}
else
{
check( false );
}
}
void
FHoudiniParameterDetails::CreateWidget( TSharedPtr< SVerticalBox > VerticalBox, class UHoudiniAssetParameter* InParam )
{
check( InParam );
if ( auto ParamChoice = Cast<UHoudiniAssetParameterChoice>( InParam ) )
{
CreateWidgetChoice( VerticalBox, *ParamChoice );
}
else if ( auto ParamToggle = Cast<UHoudiniAssetParameterToggle>( InParam ) )
{
CreateWidgetToggle( VerticalBox, *ParamToggle );
}
else
{
check( false );
}
}
void
FHoudiniParameterDetails::CreateWidgetFile( IDetailCategoryBuilder & LocalDetailCategoryBuilder, class UHoudiniAssetParameterFile& InParam )
{
FDetailWidgetRow& Row = LocalDetailCategoryBuilder.AddCustomRow( FText::GetEmpty() );
// Create the standard parameter name widget.
CreateNameWidget( &InParam, Row, true );
TSharedRef<SVerticalBox> VerticalBox = SNew( SVerticalBox );
FString FileTypeWidgetFilter = TEXT( "All files (*.*)|*.*" );
if ( !InParam.Filters.IsEmpty() )
FileTypeWidgetFilter = FString::Printf( TEXT( "%s files (*.%s)|*.%s" ), *InParam.Filters, *InParam.Filters, *InParam.Filters );
FString BrowseWidgetDirectory = FEditorDirectories::Get().GetLastDirectory( ELastDirectory::GENERIC_OPEN );
for ( int32 Idx = 0; Idx < InParam.GetTupleSize(); ++Idx )
{
FString FileWidgetPath = InParam.Values[Idx];
FString FileWidgetBrowsePath = BrowseWidgetDirectory;
if ( !FileWidgetPath.IsEmpty() )
{
FString FileWidgetDirPath = FPaths::GetPath( FileWidgetPath );
if ( !FileWidgetDirPath.IsEmpty() )
FileWidgetBrowsePath = FileWidgetDirPath;
}
VerticalBox->AddSlot().Padding( 2, 2, 5, 2 )
[
SNew( SNewFilePathPicker )
.BrowseButtonImage( FEditorStyle::GetBrush( "PropertyWindow.Button_Ellipsis" ) )
.BrowseButtonStyle( FEditorStyle::Get(), "HoverHintOnly" )
.BrowseButtonToolTip( LOCTEXT( "FileButtonToolTipText", "Choose a file" ) )
.BrowseDirectory( FileWidgetBrowsePath )
.BrowseTitle( LOCTEXT( "PropertyEditorTitle", "File picker..." ) )
.FilePath( FileWidgetPath )
.FileTypeFilter( FileTypeWidgetFilter )
.OnPathPicked( FOnPathPicked::CreateUObject(
&InParam, &UHoudiniAssetParameterFile::HandleFilePathPickerPathPicked, Idx ) )
.IsNewFile( !InParam.IsReadOnly )
];
}
Row.ValueWidget.Widget = VerticalBox;
Row.ValueWidget.MinDesiredWidth( HAPI_UNREAL_DESIRED_ROW_VALUE_WIDGET_WIDTH );
Row.ValueWidget.Widget->SetEnabled( !InParam.bIsDisabled );
}
void
FHoudiniParameterDetails::CreateWidgetFolder( IDetailCategoryBuilder & LocalDetailCategoryBuilder, class UHoudiniAssetParameterFolder& InParam )
{
if ( InParam.ParentParameter && !InParam.ParentParameter->IsPendingKill() && InParam.ParentParameter->IsActiveChildParameter( &InParam ) )
{
// Recursively create all child parameters.
for ( UHoudiniAssetParameter * ChildParam : InParam.ChildParameters )
{
if ( ChildParam && !ChildParam->IsPendingKill() )
FHoudiniParameterDetails::CreateWidget(LocalDetailCategoryBuilder, ChildParam);
}
}
}
void
FHoudiniParameterDetails::CreateWidgetFolderList( IDetailCategoryBuilder & LocalDetailCategoryBuilder, class UHoudiniAssetParameterFolderList& InParam )
{
TWeakObjectPtr<UHoudiniAssetParameterFolderList> MyParam( &InParam );
TSharedRef< SHorizontalBox > HorizontalBox = SNew( SHorizontalBox );
LocalDetailCategoryBuilder.AddCustomRow( FText::GetEmpty() )
[
SAssignNew(HorizontalBox, SHorizontalBox)
];
for ( int32 ParameterIdx = 0; ParameterIdx < InParam.ChildParameters.Num(); ++ParameterIdx )
{
UHoudiniAssetParameter * HoudiniAssetParameterChild = InParam.ChildParameters[ ParameterIdx ];
if ( !HoudiniAssetParameterChild || HoudiniAssetParameterChild->IsPendingKill() )
continue;
if ( HoudiniAssetParameterChild->IsA( UHoudiniAssetParameterFolder::StaticClass() ) )
{
FText ParameterLabelText = FText::FromString( HoudiniAssetParameterChild->GetParameterLabel() );
FText ParameterToolTip = GetParameterTooltip( HoudiniAssetParameterChild );
HorizontalBox->AddSlot().Padding( 0, 2, 0, 2 )
[
SNew( SButton )
.VAlign( VAlign_Center )
.HAlign( HAlign_Center )
.Text( ParameterLabelText )
.ToolTipText( ParameterToolTip )
.OnClicked( FOnClicked::CreateLambda( [=]() {
if ( MyParam.IsValid() )
{
MyParam->ActiveChildParameter = ParameterIdx;
MyParam->OnParamStateChanged();
}
return FReply::Handled();
}))
];
}
}
// Recursively create all child parameters.
for (UHoudiniAssetParameter * ChildParam : InParam.ChildParameters)
{
if ( ChildParam && !ChildParam->IsPendingKill() )
FHoudiniParameterDetails::CreateWidget(LocalDetailCategoryBuilder, ChildParam);
}
if ( InParam.ChildParameters.Num() > 1 )
{
TSharedPtr< STextBlock > TextBlock;
LocalDetailCategoryBuilder.AddCustomRow( FText::GetEmpty() )
[
SAssignNew( TextBlock, STextBlock )
.Text( FText::GetEmpty() )
.ToolTipText( FText::GetEmpty() )
.Font( FEditorStyle::GetFontStyle( TEXT( "PropertyWindow.NormalFont" ) ) )
.WrapTextAt( HAPI_UNREAL_DESIRED_ROW_FULL_WIDGET_WIDTH )
];
if ( TextBlock.IsValid() )
TextBlock->SetEnabled( !InParam.bIsDisabled );
}
}
void
FHoudiniParameterDetails::CreateWidgetMultiparm( IDetailCategoryBuilder & LocalDetailCategoryBuilder, class UHoudiniAssetParameterMultiparm& InParam )
{
FDetailWidgetRow & Row = LocalDetailCategoryBuilder.AddCustomRow( FText::GetEmpty() );
// Create the standard parameter name widget.
CreateNameWidget( &InParam, Row, true );
TSharedRef< SHorizontalBox > HorizontalBox = SNew( SHorizontalBox );
TSharedPtr< SNumericEntryBox< int32 > > NumericEntryBox;
HorizontalBox->AddSlot().Padding( 2, 2, 5, 2 )
[
SAssignNew( NumericEntryBox, SNumericEntryBox< int32 > )
.AllowSpin( true )
.Font( FEditorStyle::GetFontStyle( TEXT( "PropertyWindow.NormalFont" ) ) )
.Value( TAttribute< TOptional< int32 > >::Create( TAttribute< TOptional< int32 > >::FGetter::CreateUObject(
&InParam, &UHoudiniAssetParameterMultiparm::GetValue ) ) )
.OnValueChanged( SNumericEntryBox<int32>::FOnValueChanged::CreateUObject(
&InParam, &UHoudiniAssetParameterMultiparm::SetValue ) )
];
HorizontalBox->AddSlot().AutoWidth().Padding( 2.0f, 0.0f )
[
PropertyCustomizationHelpers::MakeAddButton( FSimpleDelegate::CreateUObject(
&InParam, &UHoudiniAssetParameterMultiparm::AddElement, true, true ),
LOCTEXT( "AddAnotherMultiparmInstanceToolTip", "Add Another Instance" ) )
];
HorizontalBox->AddSlot().AutoWidth().Padding( 2.0f, 0.0f )
[
PropertyCustomizationHelpers::MakeRemoveButton( FSimpleDelegate::CreateUObject(
&InParam, &UHoudiniAssetParameterMultiparm::RemoveElement, true, true ),
LOCTEXT( "RemoveLastMultiparmInstanceToolTip", "Remove Last Instance" ) )
];
HorizontalBox->AddSlot().AutoWidth().Padding( 2.0f, 0.0f )
[
PropertyCustomizationHelpers::MakeEmptyButton( FSimpleDelegate::CreateUObject(
&InParam, &UHoudiniAssetParameterMultiparm::SetValue, 0 ),
LOCTEXT( "ClearAllMultiparmInstanesToolTip", "Clear All Instances" ) )
];
if ( NumericEntryBox.IsValid() )
NumericEntryBox->SetEnabled( !InParam.bIsDisabled );
Row.ValueWidget.Widget = HorizontalBox;
Row.ValueWidget.MinDesiredWidth( HAPI_UNREAL_DESIRED_ROW_VALUE_WIDGET_WIDTH );
// Recursively create all child parameters.
for ( UHoudiniAssetParameter * ChildParam : InParam.ChildParameters )
if ( ChildParam && !ChildParam->IsPendingKill() )
FHoudiniParameterDetails::CreateWidget( LocalDetailCategoryBuilder, ChildParam );
}
/** We need to inherit from curve editor in order to get subscription to mouse events. **/
class SHoudiniAssetParameterRampCurveEditor : public SCurveEditor
{
public:
SLATE_BEGIN_ARGS( SHoudiniAssetParameterRampCurveEditor )
: _ViewMinInput( 0.0f )
, _ViewMaxInput( 10.0f )
, _ViewMinOutput( 0.0f )
, _ViewMaxOutput( 1.0f )
, _InputSnap( 0.1f )
, _OutputSnap( 0.05f )
, _InputSnappingEnabled( false )
, _OutputSnappingEnabled( false )
, _ShowTimeInFrames( false )
, _TimelineLength( 5.0f )
, _DesiredSize( FVector2D::ZeroVector )
, _DrawCurve( true )
, _HideUI( true )
, _AllowZoomOutput( true )
, _AlwaysDisplayColorCurves( false )
, _ZoomToFitVertical( true )
, _ZoomToFitHorizontal( true )
, _ShowZoomButtons( true )
, _XAxisName()
, _YAxisName()
, _ShowInputGridNumbers( true )
, _ShowOutputGridNumbers( true )
, _ShowCurveSelector( true )
, _GridColor( FLinearColor( 0.0f, 0.0f, 0.0f, 0.3f ) )
{
_Clipping = EWidgetClipping::ClipToBounds;
}
SLATE_ATTRIBUTE(float, ViewMinInput)
SLATE_ATTRIBUTE(float, ViewMaxInput)
SLATE_ATTRIBUTE(TOptional<float>, DataMinInput)
SLATE_ATTRIBUTE(TOptional<float>, DataMaxInput)
SLATE_ATTRIBUTE(float, ViewMinOutput)
SLATE_ATTRIBUTE(float, ViewMaxOutput)
SLATE_ATTRIBUTE(float, InputSnap)
SLATE_ATTRIBUTE(float, OutputSnap)
SLATE_ATTRIBUTE(bool, InputSnappingEnabled)
SLATE_ATTRIBUTE(bool, OutputSnappingEnabled)
SLATE_ATTRIBUTE(bool, ShowTimeInFrames)
SLATE_ATTRIBUTE(float, TimelineLength)
SLATE_ATTRIBUTE(FVector2D, DesiredSize)
SLATE_ATTRIBUTE(bool, AreCurvesVisible)
SLATE_ARGUMENT(bool, DrawCurve)
SLATE_ARGUMENT(bool, HideUI)
SLATE_ARGUMENT(bool, AllowZoomOutput)
SLATE_ARGUMENT(bool, AlwaysDisplayColorCurves)
SLATE_ARGUMENT(bool, ZoomToFitVertical)
SLATE_ARGUMENT(bool, ZoomToFitHorizontal)
SLATE_ARGUMENT(bool, ShowZoomButtons)
SLATE_ARGUMENT(TOptional<FString>, XAxisName)
SLATE_ARGUMENT(TOptional<FString>, YAxisName)
SLATE_ARGUMENT(bool, ShowInputGridNumbers)
SLATE_ARGUMENT(bool, ShowOutputGridNumbers)
SLATE_ARGUMENT(bool, ShowCurveSelector)
SLATE_ARGUMENT(FLinearColor, GridColor)
SLATE_EVENT( FOnSetInputViewRange, OnSetInputViewRange )
SLATE_EVENT( FOnSetOutputViewRange, OnSetOutputViewRange )
SLATE_EVENT( FOnSetAreCurvesVisible, OnSetAreCurvesVisible )
SLATE_EVENT( FSimpleDelegate, OnCreateAsset )
SLATE_END_ARGS()
public:
/** Widget construction. **/
void Construct( const FArguments & InArgs );
protected:
/** Handle mouse up events. **/
virtual FReply OnMouseButtonUp( const FGeometry & MyGeometry, const FPointerEvent & MouseEvent ) override;
public:
/** Set parent ramp parameter. **/
void SetParentRampParameter( UHoudiniAssetParameterRamp * InHoudiniAssetParameterRamp )
{
HoudiniAssetParameterRamp = InHoudiniAssetParameterRamp;
}
protected:
/** Parent ramp parameter. **/
TWeakObjectPtr<UHoudiniAssetParameterRamp> HoudiniAssetParameterRamp;
};
void
SHoudiniAssetParameterRampCurveEditor::Construct( const FArguments & InArgs )
{
SCurveEditor::Construct( SCurveEditor::FArguments()
.ViewMinInput( InArgs._ViewMinInput )
.ViewMaxInput( InArgs._ViewMaxInput )
.ViewMinOutput( InArgs._ViewMinOutput )
.ViewMaxOutput( InArgs._ViewMaxOutput )
.XAxisName( InArgs._XAxisName )
.YAxisName( InArgs._YAxisName )
.HideUI( InArgs._HideUI )
.DrawCurve( InArgs._DrawCurve )
.TimelineLength( InArgs._TimelineLength )
.AllowZoomOutput( InArgs._AllowZoomOutput )
.ShowInputGridNumbers( InArgs._ShowInputGridNumbers )
.ShowOutputGridNumbers( InArgs._ShowOutputGridNumbers )
.ShowZoomButtons( InArgs._ShowZoomButtons )
.ZoomToFitHorizontal( InArgs._ZoomToFitHorizontal )
.ZoomToFitVertical( InArgs._ZoomToFitVertical )
);
HoudiniAssetParameterRamp = nullptr;
UCurveEditorSettings * CurveEditorSettings = GetSettings();
if ( CurveEditorSettings )
{
//CurveEditorSettings->SetCurveVisibility( ECurveEditorCurveVisibility::AllCurves );
CurveEditorSettings->SetTangentVisibility( ECurveEditorTangentVisibility::NoTangents );
}
}
FReply
SHoudiniAssetParameterRampCurveEditor::OnMouseButtonUp(
const FGeometry & MyGeometry,
const FPointerEvent & MouseEvent )
{
FReply Reply = SCurveEditor::OnMouseButtonUp( MyGeometry, MouseEvent );
if ( HoudiniAssetParameterRamp.IsValid() )
HoudiniAssetParameterRamp->OnCurveEditingFinished();
return Reply;
}
void
FHoudiniParameterDetails::CreateWidgetRamp( IDetailCategoryBuilder & LocalDetailCategoryBuilder, class UHoudiniAssetParameterRamp& InParam )
{
TWeakObjectPtr<UHoudiniAssetParameterRamp> MyParam( &InParam );
FDetailWidgetRow & Row = LocalDetailCategoryBuilder.AddCustomRow( FText::GetEmpty() );
// Create the standard parameter name widget.
CreateNameWidget( &InParam, Row, true );
TSharedRef< SHorizontalBox > HorizontalBox = SNew( SHorizontalBox );
FString CurveAxisTextX = TEXT( "" );
FString CurveAxisTextY = TEXT( "" );
UClass * CurveClass = nullptr;
if ( InParam.bIsFloatRamp )
{
CurveAxisTextX = TEXT( HAPI_UNREAL_RAMP_FLOAT_AXIS_X );
CurveAxisTextY = TEXT( HAPI_UNREAL_RAMP_FLOAT_AXIS_Y );
CurveClass = UHoudiniAssetParameterRampCurveFloat::StaticClass();
}
else
{
CurveAxisTextX = TEXT( HAPI_UNREAL_RAMP_COLOR_AXIS_X );
CurveAxisTextY = TEXT( HAPI_UNREAL_RAMP_COLOR_AXIS_Y );
CurveClass = UHoudiniAssetParameterRampCurveColor::StaticClass();
}
HorizontalBox->AddSlot().Padding( 2, 2, 5, 2 )
[
SNew( SBorder )
.VAlign( VAlign_Fill )
[
SAssignNew( InParam.CurveEditor, SHoudiniAssetParameterRampCurveEditor )
.ViewMinInput( 0.0f )
.ViewMaxInput( 1.0f )
.HideUI( true )
.DrawCurve( true )
.ViewMinInput( 0.0f )
.ViewMaxInput( 1.0f )
.ViewMinOutput( 0.0f )
.ViewMaxOutput( 1.0f )
.TimelineLength( 1.0f )
.AllowZoomOutput( false )
.ShowInputGridNumbers( false )
.ShowOutputGridNumbers( false )
.ShowZoomButtons( false )
.ZoomToFitHorizontal( false )
.ZoomToFitVertical( false )
.XAxisName( CurveAxisTextX )
.YAxisName( CurveAxisTextY )
.ShowCurveSelector( false )
]
];
// Set callback for curve editor events.
TSharedPtr< SHoudiniAssetParameterRampCurveEditor > HoudiniRampEditor = StaticCastSharedPtr<SHoudiniAssetParameterRampCurveEditor>(InParam.CurveEditor );
if ( HoudiniRampEditor.IsValid() )
HoudiniRampEditor->SetParentRampParameter( &InParam );
if ( InParam.bIsFloatRamp )
{
if ( !InParam.HoudiniAssetParameterRampCurveFloat
&& (InParam.PrimaryObject && !InParam.PrimaryObject->IsPendingKill() ) )
{
InParam.HoudiniAssetParameterRampCurveFloat = Cast< UHoudiniAssetParameterRampCurveFloat >(
NewObject< UHoudiniAssetParameterRampCurveFloat >(
InParam.PrimaryObject, UHoudiniAssetParameterRampCurveFloat::StaticClass(),
NAME_None, RF_Transactional | RF_Public ) );
InParam.HoudiniAssetParameterRampCurveFloat->SetParentRampParameter( &InParam );
}
// Set curve values.
InParam.GenerateCurvePoints();
// Set the curve that is being edited.
InParam.CurveEditor->SetCurveOwner( InParam.HoudiniAssetParameterRampCurveFloat, true );
}
else
{
if ( !InParam.HoudiniAssetParameterRampCurveColor
&& ( InParam.PrimaryObject && !InParam.PrimaryObject->IsPendingKill() ) )
{
InParam.HoudiniAssetParameterRampCurveColor = Cast< UHoudiniAssetParameterRampCurveColor >(
NewObject< UHoudiniAssetParameterRampCurveColor >(
InParam.PrimaryObject, UHoudiniAssetParameterRampCurveColor::StaticClass(),
NAME_None, RF_Transactional | RF_Public ) );
InParam.HoudiniAssetParameterRampCurveColor->SetParentRampParameter( &InParam );
}
// Set curve values.
InParam.GenerateCurvePoints();
// Set the curve that is being edited.
InParam.CurveEditor->SetCurveOwner( InParam.HoudiniAssetParameterRampCurveColor, true );
}
Row.ValueWidget.Widget = HorizontalBox;
Row.ValueWidget.MinDesiredWidth( HAPI_UNREAL_DESIRED_ROW_VALUE_WIDGET_WIDTH );
// Recursively create all child parameters.
for ( UHoudiniAssetParameter * ChildParam : InParam.ChildParameters )
if ( ChildParam && !ChildParam->IsPendingKill() )
FHoudiniParameterDetails::CreateWidget( LocalDetailCategoryBuilder, ChildParam );
}
void
FHoudiniParameterDetails::CreateWidgetButton( IDetailCategoryBuilder & LocalDetailCategoryBuilder, class UHoudiniAssetParameterButton& InParam )
{
TWeakObjectPtr<UHoudiniAssetParameterButton> MyParam( &InParam );
FDetailWidgetRow& Row = LocalDetailCategoryBuilder.AddCustomRow( FText::GetEmpty() );
// Create the standard parameter name widget.
CreateNameWidget( &InParam, Row, true );
FText ParameterLabelText = FText::FromString( InParam.GetParameterLabel() );
FText ParameterTooltip = GetParameterTooltip( &InParam );
TSharedRef< SHorizontalBox > HorizontalBox = SNew( SHorizontalBox );
TSharedPtr< SButton > Button;
HorizontalBox->AddSlot().Padding( 1, 2, 4, 2 )
[
SAssignNew( Button, SButton )
.VAlign( VAlign_Center )
.HAlign( HAlign_Center )
.Text( ParameterLabelText )
.ToolTipText( ParameterTooltip )
.OnClicked( FOnClicked::CreateLambda( [=]() {
if ( MyParam.IsValid() )
{
// There's no undo operation for button.
MyParam->MarkChanged();
}
return FReply::Handled();
}))
];
if ( Button.IsValid() )
Button->SetEnabled( !InParam.bIsDisabled );
Row.ValueWidget.Widget = HorizontalBox;
Row.ValueWidget.MinDesiredWidth( HAPI_UNREAL_DESIRED_ROW_VALUE_WIDGET_WIDTH );
}
void
FHoudiniParameterDetails::CreateWidgetChoice( IDetailCategoryBuilder & LocalDetailCategoryBuilder, class UHoudiniAssetParameterChoice& InParam )
{
FDetailWidgetRow & Row = LocalDetailCategoryBuilder.AddCustomRow( FText::GetEmpty() );
// Create the standard parameter name widget.
CreateNameWidget( &InParam, Row, true );
TSharedRef< SHorizontalBox > HorizontalBox = SNew( SHorizontalBox );
TSharedPtr< SComboBox< TSharedPtr< FString > > > ComboBox;
TWeakObjectPtr<UHoudiniAssetParameterChoice> MyParam( &InParam );
HorizontalBox->AddSlot().Padding( 2, 2, 5, 2 )
[
SAssignNew( ComboBox, SComboBox< TSharedPtr< FString > > )
.OptionsSource( &InParam.StringChoiceLabels )
.InitiallySelectedItem( InParam.StringChoiceLabels[InParam.CurrentValue] )
.OnGenerateWidget( SComboBox< TSharedPtr< FString > >::FOnGenerateWidget::CreateLambda(
[]( TSharedPtr< FString > ChoiceEntry ) {
FText ChoiceEntryText = FText::FromString( *ChoiceEntry );
return SNew( STextBlock )
.Text( ChoiceEntryText )
.ToolTipText( ChoiceEntryText )
.Font( FEditorStyle::GetFontStyle( TEXT( "PropertyWindow.NormalFont" ) ) );
}))
.OnSelectionChanged( SComboBox< TSharedPtr< FString > >::FOnSelectionChanged::CreateLambda(
[=]( TSharedPtr< FString > NewChoice, ESelectInfo::Type SelectType ) {
if ( !NewChoice.IsValid() || !MyParam.IsValid() )
return;
MyParam->OnChoiceChange( NewChoice );
}))
[
SNew( STextBlock )
.Text( TAttribute< FText >::Create( TAttribute< FText >::FGetter::CreateUObject(
&InParam, &UHoudiniAssetParameterChoice::HandleChoiceContentText ) ) )
.Font( FEditorStyle::GetFontStyle( TEXT( "PropertyWindow.NormalFont" ) ) )
]
];
if ( ComboBox.IsValid() )
ComboBox->SetEnabled( !InParam.bIsDisabled );
Row.ValueWidget.Widget = HorizontalBox;
Row.ValueWidget.MinDesiredWidth( HAPI_UNREAL_DESIRED_ROW_VALUE_WIDGET_WIDTH );
}
void
FHoudiniParameterDetails::CreateWidgetChoice( TSharedPtr< SVerticalBox > VerticalBox, class UHoudiniAssetParameterChoice& InParam )
{
FText ParameterLabelText = FText::FromString( InParam.GetParameterLabel() );
FText ParameterTooltip = GetParameterTooltip( &InParam );
TWeakObjectPtr<UHoudiniAssetParameterChoice> MyParam( &InParam );
VerticalBox->AddSlot().Padding( 2, 2, 2, 2 )
[
SNew( SHorizontalBox )
+ SHorizontalBox::Slot().MaxWidth( 80 ).Padding( 7, 1, 0, 0 ).VAlign( VAlign_Center )
[
SNew( STextBlock )
.Text( ParameterLabelText )
.ToolTipText( ParameterTooltip )
.Font( FEditorStyle::GetFontStyle( TEXT( "PropertyWindow.NormalFont" ) ) )
]
+ SHorizontalBox::Slot()
[
SNew( SComboBox< TSharedPtr< FString > > )
.OptionsSource( &InParam.StringChoiceLabels )
.InitiallySelectedItem( InParam.StringChoiceLabels[InParam.CurrentValue] )
.OnGenerateWidget( SComboBox< TSharedPtr< FString > >::FOnGenerateWidget::CreateLambda(
[]( TSharedPtr< FString > ChoiceEntry ) {
FText ChoiceEntryText = FText::FromString( *ChoiceEntry );
return SNew( STextBlock )
.Text( ChoiceEntryText )
.ToolTipText( ChoiceEntryText )
.Font( FEditorStyle::GetFontStyle( TEXT( "PropertyWindow.NormalFont" ) ) );
}))
.OnSelectionChanged( SComboBox< TSharedPtr< FString > >::FOnSelectionChanged::CreateLambda(
[=]( TSharedPtr< FString > NewChoice, ESelectInfo::Type SelectType ) {
if ( !NewChoice.IsValid() || !MyParam.IsValid() )
return;
MyParam->OnChoiceChange( NewChoice );
}))
[
SNew( STextBlock )
.Text( TAttribute< FText >::Create( TAttribute< FText >::FGetter::CreateUObject(
&InParam, &UHoudiniAssetParameterChoice::HandleChoiceContentText ) ) )
.Font( FEditorStyle::GetFontStyle( TEXT( "PropertyWindow.NormalFont" ) ) )
]
]
];
}
void
FHoudiniParameterDetails::CreateWidgetColor( IDetailCategoryBuilder & LocalDetailCategoryBuilder, class UHoudiniAssetParameterColor& InParam )
{
TWeakObjectPtr<UHoudiniAssetParameterColor> MyParam( &InParam );
FDetailWidgetRow & Row = LocalDetailCategoryBuilder.AddCustomRow( FText::GetEmpty() );
// Create the standard parameter name widget.
CreateNameWidget( &InParam, Row, true );
TSharedPtr< SColorBlock > ColorBlock;
TSharedRef< SVerticalBox > VerticalBox = SNew( SVerticalBox );
VerticalBox->AddSlot().Padding( 2, 2, 5, 2 )
[
SAssignNew( ColorBlock, SColorBlock )
.Color( TAttribute< FLinearColor >::Create( TAttribute< FLinearColor >::FGetter::CreateUObject(
&InParam, &UHoudiniAssetParameterColor::GetColor ) ) )
.OnMouseButtonDown( FPointerEventHandler::CreateLambda(
[=]( const FGeometry & MyGeometry, const FPointerEvent & MouseEvent )
{
if ( MouseEvent.GetEffectingButton() != EKeys::LeftMouseButton || !MyParam.IsValid() )
return FReply::Unhandled();
FColorPickerArgs PickerArgs;
PickerArgs.ParentWidget = ColorBlock;
PickerArgs.bUseAlpha = true;
PickerArgs.DisplayGamma = TAttribute< float >::Create(
TAttribute< float >::FGetter::CreateUObject( GEngine, &UEngine::GetDisplayGamma ) );
PickerArgs.OnColorCommitted = FOnLinearColorValueChanged::CreateUObject(
MyParam.Get(), &UHoudiniAssetParameterColor::OnPaintColorChanged, true, true );
PickerArgs.InitialColorOverride = MyParam->GetColor();
PickerArgs.bOnlyRefreshOnOk = true;
OpenColorPicker( PickerArgs );
return FReply::Handled();
} ))
];
if ( ColorBlock.IsValid() )
ColorBlock->SetEnabled( !InParam.bIsDisabled );
Row.ValueWidget.Widget = VerticalBox;
Row.ValueWidget.MinDesiredWidth( HAPI_UNREAL_DESIRED_ROW_VALUE_WIDGET_WIDTH );
}
void
FHoudiniParameterDetails::CreateWidgetToggle( IDetailCategoryBuilder & LocalDetailCategoryBuilder, class UHoudiniAssetParameterToggle& InParam )
{
FDetailWidgetRow & Row = LocalDetailCategoryBuilder.AddCustomRow( FText::GetEmpty() );
FText ParameterLabelText = FText::FromString( InParam.GetParameterLabel() );
// Create the standard parameter name widget.
CreateNameWidget( &InParam, Row, false );
TSharedRef< SVerticalBox > VerticalBox = SNew( SVerticalBox );
for ( int32 Idx = 0; Idx < InParam.GetTupleSize(); ++Idx )
{
TSharedPtr< SCheckBox > CheckBox;
VerticalBox->AddSlot().Padding( 2, 2, 5, 2 )
[
SAssignNew( CheckBox, SCheckBox )
.OnCheckStateChanged( FOnCheckStateChanged::CreateUObject(
&InParam, &UHoudiniAssetParameterToggle::CheckStateChanged, Idx ) )
.IsChecked( TAttribute< ECheckBoxState >::Create(
TAttribute< ECheckBoxState >::FGetter::CreateUObject(
&InParam, &UHoudiniAssetParameterToggle::IsChecked, Idx ) ) )
.Content()
[
SNew( STextBlock )
.Text( ParameterLabelText )
.ToolTipText( GetParameterTooltip( &InParam ) )
.Font( FEditorStyle::GetFontStyle( TEXT( "PropertyWindow.NormalFont" ) ) )
]
];
if ( CheckBox.IsValid() )
CheckBox->SetEnabled( !InParam.bIsDisabled );
}
Row.ValueWidget.Widget = VerticalBox;
Row.ValueWidget.MinDesiredWidth( HAPI_UNREAL_DESIRED_ROW_VALUE_WIDGET_WIDTH );
}
void
FHoudiniParameterDetails::CreateWidgetToggle( TSharedPtr< SVerticalBox > VerticalBox, class UHoudiniAssetParameterToggle& InParam )
{
FText ParameterLabelText = FText::FromString( InParam.GetParameterLabel() );
FText ParameterTooltip = GetParameterTooltip( &InParam );
for ( int32 Idx = 0; Idx < InParam.GetTupleSize(); ++Idx )
{
VerticalBox->AddSlot().Padding( 0, 2, 0, 2 )
[
SNew( SHorizontalBox )
+SHorizontalBox::Slot().MaxWidth( 8 )
[
SNew( STextBlock )
.Text( FText::GetEmpty() )
.ToolTipText( ParameterLabelText )
.Font( FEditorStyle::GetFontStyle( TEXT( "PropertyWindow.NormalFont" ) ) )
]
+SHorizontalBox::Slot()
[
SNew( SCheckBox )
.OnCheckStateChanged( FOnCheckStateChanged::CreateUObject(
&InParam, &UHoudiniAssetParameterToggle::CheckStateChanged, Idx ) )
.IsChecked(TAttribute< ECheckBoxState >::Create(
TAttribute< ECheckBoxState >::FGetter::CreateUObject(
&InParam, &UHoudiniAssetParameterToggle::IsChecked, Idx ) ) )
.Content()
[
SNew( STextBlock )
.Text( ParameterLabelText )
.ToolTipText( ParameterTooltip )
.Font( FEditorStyle::GetFontStyle( TEXT( "PropertyWindow.NormalFont" ) ) )
]
]
];
}
}
void
FHoudiniParameterDetails::CreateWidgetFloat( IDetailCategoryBuilder & LocalDetailCategoryBuilder, class UHoudiniAssetParameterFloat& InParam )
{
TWeakObjectPtr<UHoudiniAssetParameterFloat> MyParam( &InParam );
/** Should we swap Y and Z fields (only relevant for Vector3) */
bool SwappedAxis3Vector = false;
if ( auto Settings = UHoudiniRuntimeSettings::StaticClass()->GetDefaultObject<UHoudiniRuntimeSettings>() )
{
SwappedAxis3Vector = InParam.GetTupleSize() == 3 && Settings->ImportAxis == HRSAI_Unreal;
}
if ( SwappedAxis3Vector )
{
// Ignore the swapping if that parameter has the noswap tag
if ( InParam.NoSwap )
SwappedAxis3Vector = false;
}
FDetailWidgetRow & Row = LocalDetailCategoryBuilder.AddCustomRow( FText::GetEmpty() );
// Create the standard parameter name widget.
CreateNameWidget( &InParam, Row, true );
// Helper function to find a unit from a string (name or abbreviation)
auto ParmUnit = FUnitConversion::UnitFromString( *InParam.ValueUnit );
EUnit Unit = EUnit::Unspecified;
if (FUnitConversion::Settings().ShouldDisplayUnits() && ParmUnit.IsSet())
Unit = ParmUnit.GetValue();
TSharedPtr<INumericTypeInterface<float>> paramTypeInterface;
paramTypeInterface = MakeShareable(new TNumericUnitTypeInterface<float>(Unit));
if ( InParam.GetTupleSize() == 3 )
{
TSharedRef< SVerticalBox > VerticalBox = SNew(SVerticalBox);
VerticalBox->AddSlot().Padding(2, 2, 5, 2)
[
SNew(SHorizontalBox)
+ SHorizontalBox::Slot().FillWidth(1.0f)
[
SNew(SVectorInputBox)
.bColorAxisLabels(true)
.X(TAttribute< TOptional< float > >::Create(TAttribute< TOptional< float > >::FGetter::CreateUObject(&InParam, &UHoudiniAssetParameterFloat::GetValue, 0)))
.Y(TAttribute< TOptional< float > >::Create(TAttribute< TOptional< float > >::FGetter::CreateUObject(&InParam, &UHoudiniAssetParameterFloat::GetValue, SwappedAxis3Vector ? 2 : 1)))
.Z(TAttribute< TOptional< float > >::Create(TAttribute< TOptional< float > >::FGetter::CreateUObject(&InParam, &UHoudiniAssetParameterFloat::GetValue, SwappedAxis3Vector ? 1 : 2)))
.OnXCommitted(FOnFloatValueCommitted::CreateLambda(
[=](float Val, ETextCommit::Type TextCommitType) {
MyParam->SetValue(Val, 0, true, true);
}))
.OnYCommitted(FOnFloatValueCommitted::CreateLambda(
[=](float Val, ETextCommit::Type TextCommitType) {
MyParam->SetValue(Val, SwappedAxis3Vector ? 2 : 1, true, true);
}))
.OnZCommitted(FOnFloatValueCommitted::CreateLambda(
[=](float Val, ETextCommit::Type TextCommitType) {
MyParam->SetValue(Val, SwappedAxis3Vector ? 1 : 2, true, true);
}))
.TypeInterface(paramTypeInterface)
]
+ SHorizontalBox::Slot().AutoWidth().Padding(2.0f, 0.0f).VAlign(VAlign_Center)
[
SNew(SButton)
.ToolTipText(LOCTEXT("ResetToBase", "Reset to default"))
.ButtonStyle(FEditorStyle::Get(), "NoBorder")
.ContentPadding(0)
.Visibility(EVisibility::Visible)
.OnClicked(FOnClicked::CreateUObject(
&InParam, &UHoudiniAssetParameter::OnRevertParmToDefault, -1))
[
SNew(SImage)
.Image(FEditorStyle::GetBrush("PropertyWindow.DiffersFromDefault"))
]
]
];
Row.ValueWidget.Widget = VerticalBox;
}
else
{
TSharedRef< SVerticalBox > VerticalBox = SNew( SVerticalBox );
for ( int32 Idx = 0; Idx < InParam.GetTupleSize(); ++Idx )
{
TSharedPtr< SNumericEntryBox< float > > NumericEntryBox;
VerticalBox->AddSlot().Padding( 2, 2, 5, 2 )
[
SNew(SHorizontalBox)
+ SHorizontalBox::Slot().FillWidth(1.0f)
[
SAssignNew( NumericEntryBox, SNumericEntryBox< float > )
.AllowSpin( true )
.Font( FEditorStyle::GetFontStyle( TEXT( "PropertyWindow.NormalFont" ) ) )
.MinValue( InParam.ValueMin )
.MaxValue( InParam.ValueMax )
.MinSliderValue( InParam.ValueUIMin )
.MaxSliderValue( InParam.ValueUIMax )
.Value( TAttribute< TOptional< float > >::Create( TAttribute< TOptional< float > >::FGetter::CreateUObject(
&InParam, &UHoudiniAssetParameterFloat::GetValue, Idx ) ) )
.OnValueChanged( SNumericEntryBox< float >::FOnValueChanged::CreateLambda(
[=]( float Val ) {
MyParam->SetValue( Val, Idx, false, false );
} ) )
.OnValueCommitted( SNumericEntryBox< float >::FOnValueCommitted::CreateLambda(
[=]( float Val, ETextCommit::Type TextCommitType ) {
MyParam->SetValue( Val, Idx, true, true );
} ) )
.OnBeginSliderMovement( FSimpleDelegate::CreateUObject(
&InParam, &UHoudiniAssetParameterFloat::OnSliderMovingBegin, Idx ) )
.OnEndSliderMovement( SNumericEntryBox< float >::FOnValueChanged::CreateUObject(
&InParam, &UHoudiniAssetParameterFloat::OnSliderMovingFinish, Idx ) )
.SliderExponent( 1.0f )
.TypeInterface( paramTypeInterface )
]
+ SHorizontalBox::Slot().AutoWidth().Padding(2.0f, 0.0f).VAlign(VAlign_Center)
[
SNew(SButton)
.ToolTipText(LOCTEXT("ResetToBase", "Reset to default"))
.ButtonStyle(FEditorStyle::Get(), "NoBorder")
.ContentPadding(0)
.Visibility(EVisibility::Visible)
.OnClicked(FOnClicked::CreateUObject(
&InParam, &UHoudiniAssetParameter::OnRevertParmToDefault, Idx))
[
SNew(SImage)
.Image(FEditorStyle::GetBrush("PropertyWindow.DiffersFromDefault"))
]
]
];
}
Row.ValueWidget.Widget = VerticalBox;
}
Row.ValueWidget.MinDesiredWidth( HAPI_UNREAL_DESIRED_ROW_VALUE_WIDGET_WIDTH );
Row.ValueWidget.Widget->SetEnabled( !InParam.bIsDisabled );
}
void
FHoudiniParameterDetails::CreateWidgetInt( IDetailCategoryBuilder & LocalDetailCategoryBuilder, class UHoudiniAssetParameterInt& InParam )
{
TWeakObjectPtr<UHoudiniAssetParameterInt> MyParam( &InParam );
FDetailWidgetRow & Row = LocalDetailCategoryBuilder.AddCustomRow( FText::GetEmpty() );
// Create the standard parameter name widget.
CreateNameWidget( &InParam, Row, true );
TSharedRef< SVerticalBox > VerticalBox = SNew( SVerticalBox );
// Helper function to find a unit from a string (name or abbreviation)
auto ParmUnit = FUnitConversion::UnitFromString( *InParam.ValueUnit );
EUnit Unit = EUnit::Unspecified;
if (FUnitConversion::Settings().ShouldDisplayUnits() && ParmUnit.IsSet())
Unit = ParmUnit.GetValue();
TSharedPtr<INumericTypeInterface<int32>> paramTypeInterface;
paramTypeInterface = MakeShareable(new TNumericUnitTypeInterface<int32>(Unit));
for ( int32 Idx = 0; Idx < InParam.GetTupleSize(); ++Idx )
{
TSharedPtr< SNumericEntryBox< int32 > > NumericEntryBox;
VerticalBox->AddSlot().Padding( 2, 2, 5, 2 )
[
SNew(SHorizontalBox)
+ SHorizontalBox::Slot().FillWidth(1.0f)
[
SAssignNew( NumericEntryBox, SNumericEntryBox< int32 > )
.AllowSpin( true )
.Font( FEditorStyle::GetFontStyle( TEXT( "PropertyWindow.NormalFont" ) ) )
.MinValue( InParam.ValueMin )
.MaxValue( InParam.ValueMax )
.MinSliderValue( InParam.ValueUIMin )
.MaxSliderValue( InParam.ValueUIMax )
.Value( TAttribute< TOptional< int32 > >::Create(
TAttribute< TOptional< int32 > >::FGetter::CreateUObject(
&InParam, &UHoudiniAssetParameterInt::GetValue, Idx ) ) )
.OnValueChanged( SNumericEntryBox< int32 >::FOnValueChanged::CreateLambda(
[=]( int32 Val ) {
MyParam->SetValue( Val, Idx, false, false );
} ) )
.OnValueCommitted( SNumericEntryBox< int32 >::FOnValueCommitted::CreateLambda(
[=]( float Val, ETextCommit::Type TextCommitType ) {
MyParam->SetValue( Val, Idx, true, true );
} ) )
.OnBeginSliderMovement( FSimpleDelegate::CreateUObject(
&InParam, &UHoudiniAssetParameterInt::OnSliderMovingBegin, Idx ) )
.OnEndSliderMovement( SNumericEntryBox< int32 >::FOnValueChanged::CreateUObject(
&InParam, &UHoudiniAssetParameterInt::OnSliderMovingFinish, Idx ) )
.SliderExponent( 1.0f )
.TypeInterface(paramTypeInterface)
]
+ SHorizontalBox::Slot().AutoWidth().Padding(2.0f, 0.0f).VAlign(VAlign_Center)
[
SNew(SButton)
.ToolTipText(LOCTEXT("ResetToBase", "Reset to default"))
.ButtonStyle(FEditorStyle::Get(), "NoBorder")
.ContentPadding(0)
.Visibility(EVisibility::Visible)
.OnClicked(FOnClicked::CreateUObject(
&InParam, &UHoudiniAssetParameter::OnRevertParmToDefault, Idx))
[
SNew(SImage)
.Image(FEditorStyle::GetBrush("PropertyWindow.DiffersFromDefault"))
]
]
];
if ( NumericEntryBox.IsValid() )
NumericEntryBox->SetEnabled( !InParam.bIsDisabled );
}
Row.ValueWidget.Widget = VerticalBox;
Row.ValueWidget.MinDesiredWidth( HAPI_UNREAL_DESIRED_ROW_VALUE_WIDGET_WIDTH );
}
void
FHoudiniParameterDetails::CreateWidgetInstanceInput( IDetailCategoryBuilder & LocalDetailCategoryBuilder, class UHoudiniAssetInstanceInput& InParam )
{
TWeakObjectPtr<UHoudiniAssetInstanceInput> MyParam(&InParam);
if (!MyParam.IsValid())
return;
// Get thumbnail pool for this builder.
IDetailLayoutBuilder & DetailLayoutBuilder = LocalDetailCategoryBuilder.GetParentLayout();
TSharedPtr< FAssetThumbnailPool > AssetThumbnailPool = DetailLayoutBuilder.GetThumbnailPool();
// Classes allowed by instanced inputs.
const TArray< const UClass * > AllowedClasses = {
UStaticMesh::StaticClass(), AActor::StaticClass(), UBlueprint::StaticClass(),
USoundBase::StaticClass(), UParticleSystem::StaticClass(), USkeletalMesh::StaticClass() };
const int32 FieldCount = InParam.InstanceInputFields.Num();
for ( int32 FieldIdx = 0; FieldIdx < FieldCount; ++FieldIdx )
{
UHoudiniAssetInstanceInputField * HoudiniAssetInstanceInputField = InParam.InstanceInputFields[ FieldIdx ];
if ( !HoudiniAssetInstanceInputField || HoudiniAssetInstanceInputField->IsPendingKill() )
continue;
const int32 VariationCount = HoudiniAssetInstanceInputField->InstanceVariationCount();
for( int32 VariationIdx = 0; VariationIdx < VariationCount; VariationIdx++ )
{
UObject * InstancedObject = HoudiniAssetInstanceInputField->GetInstanceVariation( VariationIdx );
if ( !InstancedObject || InstancedObject->IsPendingKill() )
{
HOUDINI_LOG_WARNING( TEXT("Null Object found for instance variation %d"), VariationIdx );
continue;
}
// Create thumbnail for this object.
TSharedPtr< FAssetThumbnail > StaticMeshThumbnail =
MakeShareable( new FAssetThumbnail( InstancedObject, 64, 64, AssetThumbnailPool ) );
TSharedRef< SVerticalBox > PickerVerticalBox = SNew( SVerticalBox );
TSharedPtr< SHorizontalBox > PickerHorizontalBox = nullptr;
TSharedPtr< SBorder > StaticMeshThumbnailBorder;
FString FieldLabel = InParam.GetFieldLabel(FieldIdx, VariationIdx);
IDetailGroup& DetailGroup = LocalDetailCategoryBuilder.AddGroup(FName(*FieldLabel), FText::FromString(FieldLabel));
DetailGroup.AddWidgetRow()
.NameContent()
[
SNew(SSpacer)
.Size(FVector2D(250, 64))
]
.ValueContent()
.MinDesiredWidth(HAPI_UNREAL_DESIRED_ROW_VALUE_WIDGET_WIDTH)
[
PickerVerticalBox
];
TWeakObjectPtr<UHoudiniAssetInstanceInputField> InputFieldPtr( HoudiniAssetInstanceInputField );
PickerVerticalBox->AddSlot().Padding( 0, 2 ).AutoHeight()
[
SNew( SAssetDropTarget )
.OnIsAssetAcceptableForDrop( SAssetDropTarget::FIsAssetAcceptableForDrop::CreateLambda(
[=]( const UObject* Obj ) {
for ( auto Klass : AllowedClasses )
{
if ( Obj && Obj->IsA( Klass ) )
return true;
}
return false;
})
)
.OnAssetDropped( SAssetDropTarget::FOnAssetDropped::CreateUObject(
&InParam, &UHoudiniAssetInstanceInput::OnStaticMeshDropped, HoudiniAssetInstanceInputField, FieldIdx, VariationIdx ) )
[
SAssignNew( PickerHorizontalBox, SHorizontalBox )
]
];
PickerHorizontalBox->AddSlot().Padding( 0.0f, 0.0f, 2.0f, 0.0f ).AutoWidth()
[
SAssignNew( StaticMeshThumbnailBorder, SBorder )
.Padding( 5.0f )
.OnMouseDoubleClick( FPointerEventHandler::CreateUObject(
&InParam, &UHoudiniAssetInstanceInput::OnThumbnailDoubleClick, InstancedObject ) )
[
SNew( SBox )
.WidthOverride( 64 )
.HeightOverride( 64 )
.ToolTipText( FText::FromString( InstancedObject->GetPathName() ) )
[
StaticMeshThumbnail->MakeThumbnailWidget()
]
]
];
StaticMeshThumbnailBorder->SetBorderImage( TAttribute< const FSlateBrush * >::Create(
TAttribute< const FSlateBrush * >::FGetter::CreateLambda([=]() {
if ( StaticMeshThumbnailBorder.IsValid() && StaticMeshThumbnailBorder->IsHovered() )
return FEditorStyle::GetBrush( "PropertyEditor.AssetThumbnailLight" );
else
return FEditorStyle::GetBrush( "PropertyEditor.AssetThumbnailShadow" );
} ) ) );
PickerHorizontalBox->AddSlot().AutoWidth().Padding( 0.0f, 28.0f, 0.0f, 28.0f )
[
PropertyCustomizationHelpers::MakeAddButton(
FSimpleDelegate::CreateUObject(
&InParam, &UHoudiniAssetInstanceInput::OnAddInstanceVariation,
HoudiniAssetInstanceInputField, VariationIdx ),
LOCTEXT("AddAnotherInstanceToolTip", "Add Another Instance" ) )
];
PickerHorizontalBox->AddSlot().AutoWidth().Padding( 2.0f, 28.0f, 4.0f, 28.0f )
[
PropertyCustomizationHelpers::MakeRemoveButton(
FSimpleDelegate::CreateUObject(
&InParam, &UHoudiniAssetInstanceInput::OnRemoveInstanceVariation,
HoudiniAssetInstanceInputField, VariationIdx ),
LOCTEXT("RemoveLastInstanceToolTip", "Remove Last Instance"))
];
TSharedPtr< SComboButton > AssetComboButton;
TSharedPtr< SHorizontalBox > ButtonBox;
PickerHorizontalBox->AddSlot()
.FillWidth( 10.0f )
.Padding( 0.0f, 4.0f, 4.0f, 4.0f )
.VAlign( VAlign_Center )
[
SNew( SVerticalBox )
+SVerticalBox::Slot()
.HAlign( HAlign_Fill )
[
SAssignNew( ButtonBox, SHorizontalBox )
+SHorizontalBox::Slot()
[
SAssignNew( AssetComboButton, SComboButton )
//.ToolTipText( this, &FHoudiniAssetComponentDetails::OnGetToolTip )
.ButtonStyle( FEditorStyle::Get(), "PropertyEditor.AssetComboStyle" )
.ForegroundColor( FEditorStyle::GetColor( "PropertyEditor.AssetName.ColorAndOpacity" ) )
.OnMenuOpenChanged( FOnIsOpenChanged::CreateUObject(
&InParam, &UHoudiniAssetInstanceInput::ChangedStaticMeshComboButton,
HoudiniAssetInstanceInputField, FieldIdx, VariationIdx ) )
.ContentPadding( 2.0f )
.ButtonContent()
[
SNew( STextBlock )
.TextStyle( FEditorStyle::Get(), "PropertyEditor.AssetClass" )
.Font( FEditorStyle::GetFontStyle( FName( TEXT( "PropertyWindow.NormalFont" ) ) ) )
.Text( FText::FromString(InstancedObject->GetName() ) )
]
]
]
];
// Create asset picker for this combo button.
{
TArray< UFactory * > NewAssetFactories;
TSharedRef< SWidget > PropertyMenuAssetPicker =
PropertyCustomizationHelpers::MakeAssetPickerWithMenu(
FAssetData( InstancedObject ), true,
AllowedClasses, NewAssetFactories, FOnShouldFilterAsset(),
FOnAssetSelected::CreateLambda( [=]( const FAssetData& AssetData ) {
if ( AssetComboButton.IsValid() && MyParam.IsValid() && InputFieldPtr.IsValid() )
{
AssetComboButton->SetIsOpen( false );
UObject * Object = AssetData.GetAsset();
MyParam->OnStaticMeshDropped( Object, InputFieldPtr.Get(), FieldIdx, VariationIdx );
}
}),
FSimpleDelegate::CreateUObject(
&InParam, &UHoudiniAssetInstanceInput::CloseStaticMeshComboButton,
HoudiniAssetInstanceInputField, FieldIdx, VariationIdx ) );
AssetComboButton->SetMenuContent( PropertyMenuAssetPicker );
}
// Create tooltip.
FFormatNamedArguments Args;
Args.Add( TEXT( "Asset" ), FText::FromString( InstancedObject->GetName() ) );
FText StaticMeshTooltip =
FText::Format( LOCTEXT( "BrowseToSpecificAssetInContentBrowser", "Browse to '{Asset}' in Content Browser" ), Args );
ButtonBox->AddSlot()
.AutoWidth()
.Padding( 2.0f, 0.0f )
.VAlign( VAlign_Center )
[
PropertyCustomizationHelpers::MakeBrowseButton(
FSimpleDelegate::CreateUObject( &InParam, &UHoudiniAssetInstanceInput::OnInstancedObjectBrowse, InstancedObject ),
TAttribute< FText >( StaticMeshTooltip ) )
];
ButtonBox->AddSlot()
.AutoWidth()
.Padding( 2.0f, 0.0f )
.VAlign( VAlign_Center )
[
SNew( SButton )
.ToolTipText( LOCTEXT( "ResetToBase", "Reset to default static mesh" ) )
.ButtonStyle( FEditorStyle::Get(), "NoBorder" )
.ContentPadding( 0 )
.Visibility( EVisibility::Visible )
.OnClicked( FOnClicked::CreateUObject(
&InParam, &UHoudiniAssetInstanceInput::OnResetStaticMeshClicked,
HoudiniAssetInstanceInputField, FieldIdx, VariationIdx ) )
[
SNew( SImage )
.Image( FEditorStyle::GetBrush( "PropertyWindow.DiffersFromDefault" ) )
]
];
TSharedRef< SVerticalBox > OffsetVerticalBox = SNew( SVerticalBox );
FText LabelRotationText = LOCTEXT( "HoudiniRotationOffset", "Rotation Offset" );
DetailGroup.AddWidgetRow()
.NameContent()
[
SNew( STextBlock )
.Text( LabelRotationText )
.ToolTipText( LabelRotationText )
.Font( FEditorStyle::GetFontStyle( TEXT( "PropertyWindow.NormalFont" ) ) )
]
.ValueContent()
.MinDesiredWidth( HAPI_UNREAL_DESIRED_ROW_VALUE_WIDGET_WIDTH - 17 )
[
SNew( SHorizontalBox )
+ SHorizontalBox::Slot().MaxWidth( HAPI_UNREAL_DESIRED_ROW_VALUE_WIDGET_WIDTH - 17 )
[
SNew( SRotatorInputBox )
.AllowSpin( true )
.bColorAxisLabels( true )
.Roll( TAttribute< TOptional< float > >::Create(
TAttribute< TOptional< float > >::FGetter::CreateUObject(
&InParam, &UHoudiniAssetInstanceInput::GetRotationRoll, HoudiniAssetInstanceInputField, VariationIdx ) ) )
.Pitch( TAttribute< TOptional< float> >::Create(
TAttribute< TOptional< float > >::FGetter::CreateUObject(
&InParam, &UHoudiniAssetInstanceInput::GetRotationPitch, HoudiniAssetInstanceInputField, VariationIdx ) ) )
.Yaw( TAttribute<TOptional< float > >::Create(
TAttribute< TOptional< float > >::FGetter::CreateUObject(
&InParam, &UHoudiniAssetInstanceInput::GetRotationYaw, HoudiniAssetInstanceInputField, VariationIdx ) ) )
.OnRollChanged( FOnFloatValueChanged::CreateUObject(
&InParam, &UHoudiniAssetInstanceInput::SetRotationRoll, HoudiniAssetInstanceInputField, VariationIdx ) )
.OnPitchChanged( FOnFloatValueChanged::CreateUObject(
&InParam, &UHoudiniAssetInstanceInput::SetRotationPitch, HoudiniAssetInstanceInputField, VariationIdx ) )
.OnYawChanged( FOnFloatValueChanged::CreateUObject(
&InParam, &UHoudiniAssetInstanceInput::SetRotationYaw, HoudiniAssetInstanceInputField, VariationIdx ) )
]
];
FText LabelScaleText = LOCTEXT( "HoudiniScaleOffset", "Scale Offset" );
DetailGroup.AddWidgetRow()
.NameContent()
[
SNew( STextBlock )
.Text( LabelScaleText )
.ToolTipText( LabelScaleText )
.Font( FEditorStyle::GetFontStyle( TEXT( "PropertyWindow.NormalFont" ) ) )
]
.ValueContent()
.MinDesiredWidth( HAPI_UNREAL_DESIRED_ROW_VALUE_WIDGET_WIDTH )
[
SNew( SHorizontalBox )
+ SHorizontalBox::Slot().MaxWidth( HAPI_UNREAL_DESIRED_ROW_VALUE_WIDGET_WIDTH )
[
SNew( SVectorInputBox )
.bColorAxisLabels( true )
.X( TAttribute< TOptional< float > >::Create(
TAttribute< TOptional< float > >::FGetter::CreateUObject(
&InParam, &UHoudiniAssetInstanceInput::GetScaleX, HoudiniAssetInstanceInputField, VariationIdx ) ) )
.Y( TAttribute< TOptional< float > >::Create(
TAttribute< TOptional< float> >::FGetter::CreateUObject(
&InParam, &UHoudiniAssetInstanceInput::GetScaleY, HoudiniAssetInstanceInputField, VariationIdx ) ) )
.Z( TAttribute< TOptional< float> >::Create(
TAttribute< TOptional< float > >::FGetter::CreateUObject(
&InParam, &UHoudiniAssetInstanceInput::GetScaleZ, HoudiniAssetInstanceInputField, VariationIdx ) ) )
.OnXChanged( FOnFloatValueChanged::CreateUObject(
&InParam, &UHoudiniAssetInstanceInput::SetScaleX, HoudiniAssetInstanceInputField, VariationIdx ) )
.OnYChanged( FOnFloatValueChanged::CreateUObject(
&InParam, &UHoudiniAssetInstanceInput::SetScaleY, HoudiniAssetInstanceInputField, VariationIdx ) )
.OnZChanged( FOnFloatValueChanged::CreateUObject(
&InParam, &UHoudiniAssetInstanceInput::SetScaleZ, HoudiniAssetInstanceInputField, VariationIdx ) )
]
+ SHorizontalBox::Slot().AutoWidth()
[
// Add a checkbox to toggle between preserving the ratio of x,y,z components of scale when a value is entered
SNew( SCheckBox )
.Style( FEditorStyle::Get(), "TransparentCheckBox" )
.ToolTipText( LOCTEXT( "PreserveScaleToolTip", "When locked, scales uniformly based on the current xyz scale values so the object maintains its shape in each direction when scaled" ) )
.OnCheckStateChanged( FOnCheckStateChanged::CreateLambda( [=]( ECheckBoxState NewState ) {
if ( MyParam.IsValid() && InputFieldPtr.IsValid() )
MyParam->CheckStateChanged( NewState == ECheckBoxState::Checked, InputFieldPtr.Get(), VariationIdx );
}))
.IsChecked( TAttribute< ECheckBoxState >::Create(
TAttribute<ECheckBoxState>::FGetter::CreateLambda( [=]() {
if ( InputFieldPtr.IsValid() && InputFieldPtr->AreOffsetsScaledLinearly( VariationIdx ) )
return ECheckBoxState::Checked;
return ECheckBoxState::Unchecked;
})))
[
SNew( SImage )
.Image( TAttribute<const FSlateBrush*>::Create(
TAttribute<const FSlateBrush*>::FGetter::CreateLambda( [=]() {
if ( InputFieldPtr.IsValid() && InputFieldPtr->AreOffsetsScaledLinearly( VariationIdx ) )
{
return FEditorStyle::GetBrush( TEXT( "GenericLock" ) );
}
return FEditorStyle::GetBrush( TEXT( "GenericUnlock" ) );
})))
.ColorAndOpacity( FSlateColor::UseForeground() )
]
]
];
}
}
}
FMenuBuilder
FHoudiniParameterDetails::Helper_CreateCustomActorPickerWidget( UHoudiniAssetInput& InParam, const TAttribute<FText>& HeadingText, const bool& bShowCurrentSelectionSection )
{
// Custom Actor Picker showing only the desired Actor types.
// Note: Code stolen from SPropertyMenuActorPicker.cpp
FOnShouldFilterActor ActorFilter = FOnShouldFilterActor::CreateUObject( &InParam, &UHoudiniAssetInput::OnShouldFilterActor );
//FHoudiniEngineEditor & HoudiniEngineEditor = FHoudiniEngineEditor::Get();
//TSharedPtr< ISlateStyle > StyleSet = GEditor->GetSlateStyle();
FMenuBuilder MenuBuilder( true, NULL );
if ( bShowCurrentSelectionSection )
{
MenuBuilder.BeginSection( NAME_None, LOCTEXT( "CurrentActorOperationsHeader", "Current Selection" ) );
{
MenuBuilder.AddMenuEntry(
TAttribute<FText>::Create( TAttribute<FText>::FGetter::CreateUObject( &InParam, &UHoudiniAssetInput::GetCurrentSelectionText ) ),
TAttribute<FText>::Create( TAttribute<FText>::FGetter::CreateUObject( &InParam, &UHoudiniAssetInput::GetCurrentSelectionText ) ),
FSlateIcon(),//StyleSet->GetStyleSetName(), "HoudiniEngine.HoudiniEngineLogo")),
FUIAction(),
NAME_None,
EUserInterfaceActionType::Button,
NAME_None );
}
MenuBuilder.EndSection();
}
MenuBuilder.BeginSection( NAME_None, HeadingText );
{
FSceneOutlinerModule & SceneOutlinerModule =
FModuleManager::Get().LoadModuleChecked< FSceneOutlinerModule >(TEXT("SceneOutliner"));
SceneOutliner::FInitializationOptions InitOptions;
{
InitOptions.Mode = ESceneOutlinerMode::ActorPicker;
InitOptions.Filters->AddFilterPredicate(ActorFilter);
InitOptions.bFocusSearchBoxWhenOpened = true;
InitOptions.bShowCreateNewFolder = false;
// Add the gutter so we can change the selection's visibility
InitOptions.ColumnMap.Add(SceneOutliner::FBuiltInColumnTypes::Gutter(), SceneOutliner::FColumnInfo(SceneOutliner::EColumnVisibility::Visible, 0));
InitOptions.ColumnMap.Add(SceneOutliner::FBuiltInColumnTypes::Label(), SceneOutliner::FColumnInfo(SceneOutliner::EColumnVisibility::Visible, 10));
InitOptions.ColumnMap.Add(SceneOutliner::FBuiltInColumnTypes::ActorInfo(), SceneOutliner::FColumnInfo(SceneOutliner::EColumnVisibility::Visible, 20));
}
static const FVector2D SceneOutlinerWindowSize( 350.0f, 200.0f );
TSharedRef< SWidget > MenuWidget =
SNew( SBox )
.WidthOverride( SceneOutlinerWindowSize.X )
.HeightOverride( SceneOutlinerWindowSize.Y )
[
SNew( SBorder )
.BorderImage( FEditorStyle::GetBrush( "Menu.Background" ) )
[
SceneOutlinerModule.CreateSceneOutliner(
InitOptions,
FOnActorPicked::CreateUObject(
&InParam, &UHoudiniAssetInput::OnActorSelected ) )
]
];
MenuBuilder.AddWidget(MenuWidget, FText::GetEmpty(), true );
}
MenuBuilder.EndSection();
return MenuBuilder;
}
/** Create a single geometry widget for the given input object */
void FHoudiniParameterDetails::Helper_CreateGeometryWidget(
UHoudiniAssetInput& InParam, int32 AtIndex, UObject* InputObject,
TSharedPtr< FAssetThumbnailPool > AssetThumbnailPool, TSharedRef< SVerticalBox > VerticalBox )
{
TWeakObjectPtr<UHoudiniAssetInput> MyParam( &InParam );
// Create thumbnail for this static mesh.
TSharedPtr< FAssetThumbnail > StaticMeshThumbnail = MakeShareable(
new FAssetThumbnail( InputObject, 64, 64, AssetThumbnailPool ) );
TSharedPtr< SHorizontalBox > HorizontalBox = NULL;
// Drop Target: Static Mesh
VerticalBox->AddSlot().Padding( 0, 2 ).AutoHeight()
[
SNew( SAssetDropTarget )
.OnIsAssetAcceptableForDrop( SAssetDropTarget::FIsAssetAcceptableForDrop::CreateLambda(
[]( const UObject* InObject )
{ return InObject && ( InObject->IsA< UStaticMesh >() || InObject->IsA< USkeletalMesh >() ); }
) )
.OnAssetDropped( SAssetDropTarget::FOnAssetDropped::CreateUObject(
&InParam, &UHoudiniAssetInput::OnStaticMeshDropped, AtIndex ) )
[
SAssignNew( HorizontalBox, SHorizontalBox )
]
];
// Thumbnail : Static Mesh
FText ParameterLabelText = FText::FromString( InParam.GetParameterLabel() );
//FText ParameterTooltip = GetParameterTooltip( &InParam, true );
TSharedPtr< SBorder > StaticMeshThumbnailBorder;
HorizontalBox->AddSlot().Padding( 0.0f, 0.0f, 2.0f, 0.0f ).AutoWidth()
[
SAssignNew( StaticMeshThumbnailBorder, SBorder )
.Padding( 5.0f )
.OnMouseDoubleClick( FPointerEventHandler::CreateUObject( &InParam, &UHoudiniAssetInput::OnThumbnailDoubleClick, AtIndex ) )
[
SNew( SBox )
.WidthOverride( 64 )
.HeightOverride( 64 )
.ToolTipText( ParameterLabelText )
[
StaticMeshThumbnail->MakeThumbnailWidget()
]
]
];
StaticMeshThumbnailBorder->SetBorderImage( TAttribute< const FSlateBrush * >::Create(
TAttribute< const FSlateBrush * >::FGetter::CreateLambda( [StaticMeshThumbnailBorder]()
{
if ( StaticMeshThumbnailBorder.IsValid() && StaticMeshThumbnailBorder->IsHovered() )
return FEditorStyle::GetBrush( "PropertyEditor.AssetThumbnailLight" );
else
return FEditorStyle::GetBrush( "PropertyEditor.AssetThumbnailShadow" );
}
) ) );
FText MeshNameText = FText::GetEmpty();
if ( InputObject )
MeshNameText = FText::FromString( InputObject->GetName() );
// ComboBox : Static Mesh
TSharedPtr< SComboButton > StaticMeshComboButton;
TSharedPtr< SHorizontalBox > ButtonBox;
HorizontalBox->AddSlot()
.FillWidth( 1.0f )
.Padding( 0.0f, 4.0f, 4.0f, 4.0f )
.VAlign( VAlign_Center )
[
SNew( SVerticalBox )
+ SVerticalBox::Slot()
.HAlign( HAlign_Fill )
[
SAssignNew( ButtonBox, SHorizontalBox )
+ SHorizontalBox::Slot()
[
SAssignNew( StaticMeshComboButton, SComboButton )
.ButtonStyle( FEditorStyle::Get(), "PropertyEditor.AssetComboStyle" )
.ForegroundColor( FEditorStyle::GetColor( "PropertyEditor.AssetName.ColorAndOpacity" ) )
.ContentPadding( 2.0f )
.ButtonContent()
[
SNew( STextBlock )
.TextStyle( FEditorStyle::Get(), "PropertyEditor.AssetClass" )
.Font( FEditorStyle::GetFontStyle( FName( TEXT( "PropertyWindow.NormalFont" ) ) ) )
.Text( MeshNameText )
]
]
]
];
StaticMeshComboButton->SetOnGetMenuContent( FOnGetContent::CreateLambda(
[ MyParam, AtIndex, StaticMeshComboButton ]()
{
TArray< const UClass * > AllowedClasses;
AllowedClasses.Add( UStaticMesh::StaticClass() );
AllowedClasses.Add( USkeletalMesh::StaticClass() );
TArray< UFactory * > NewAssetFactories;
return PropertyCustomizationHelpers::MakeAssetPickerWithMenu(
FAssetData( MyParam->GetInputObject( AtIndex ) ),
true,
AllowedClasses,
NewAssetFactories,
FOnShouldFilterAsset(),
FOnAssetSelected::CreateLambda( [MyParam, AtIndex, StaticMeshComboButton]( const FAssetData & AssetData ) {
if ( StaticMeshComboButton.IsValid() )
{
StaticMeshComboButton->SetIsOpen( false );
UObject * Object = AssetData.GetAsset();
MyParam->OnStaticMeshDropped( Object, AtIndex );
}
} ),
FSimpleDelegate::CreateLambda( []() {} ) );
} ) );
// Create tooltip.
FFormatNamedArguments Args;
Args.Add( TEXT( "Asset" ), MeshNameText );
FText StaticMeshTooltip = FText::Format(
LOCTEXT( "BrowseToSpecificAssetInContentBrowser",
"Browse to '{Asset}' in Content Browser" ), Args );
// Button : Browse Static Mesh
ButtonBox->AddSlot()
.AutoWidth()
.Padding( 2.0f, 0.0f )
.VAlign( VAlign_Center )
[
PropertyCustomizationHelpers::MakeBrowseButton(
FSimpleDelegate::CreateUObject( &InParam, &UHoudiniAssetInput::OnStaticMeshBrowse, AtIndex ),
TAttribute< FText >( StaticMeshTooltip ) )
];
// ButtonBox : Reset
ButtonBox->AddSlot()
.AutoWidth()
.Padding( 2.0f, 0.0f )
.VAlign( VAlign_Center )
[
SNew( SButton )
.ToolTipText( LOCTEXT( "ResetToBase", "Reset to default static mesh" ) )
.ButtonStyle( FEditorStyle::Get(), "NoBorder" )
.ContentPadding( 0 )
.Visibility( EVisibility::Visible )
.OnClicked( FOnClicked::CreateUObject( &InParam, &UHoudiniAssetInput::OnResetStaticMeshClicked, AtIndex ) )
[
SNew( SImage )
.Image( FEditorStyle::GetBrush( "PropertyWindow.DiffersFromDefault" ) )
]
];
ButtonBox->AddSlot()
.Padding( 1.0f )
.VAlign( VAlign_Center )
.AutoWidth()
[
PropertyCustomizationHelpers::MakeInsertDeleteDuplicateButton(
FExecuteAction::CreateLambda( [ MyParam, AtIndex ]()
{
MyParam->OnInsertGeo( AtIndex );
}
),
FExecuteAction::CreateLambda( [MyParam, AtIndex ]()
{
MyParam->OnDeleteGeo( AtIndex );
}
),
FExecuteAction::CreateLambda( [ MyParam, AtIndex ]()
{
MyParam->OnDuplicateGeo( AtIndex );
}
) )
];
{
TSharedPtr<SButton> ExpanderArrow;
TSharedPtr<SImage> ExpanderImage;
VerticalBox->AddSlot().Padding( 0, 2 ).AutoHeight()
[
SNew( SHorizontalBox )
+SHorizontalBox::Slot()
.Padding( 1.0f )
.VAlign( VAlign_Center )
.AutoWidth()
[
SAssignNew( ExpanderArrow, SButton )
.ButtonStyle( FEditorStyle::Get(), "NoBorder" )
.ClickMethod( EButtonClickMethod::MouseDown )
.Visibility( EVisibility::Visible )
.OnClicked( FOnClicked::CreateUObject(&InParam, &UHoudiniAssetInput::OnExpandInputTransform, AtIndex ) )
[
SAssignNew( ExpanderImage, SImage )
.ColorAndOpacity( FSlateColor::UseForeground() )
]
]
+SHorizontalBox::Slot()
.Padding( 1.0f )
.VAlign( VAlign_Center )
.AutoWidth()
[
SNew( STextBlock )
.Text( LOCTEXT("GeoInputTransform", "Transform Offset") )
.ToolTipText( LOCTEXT( "GeoInputTransformTooltip", "Transform offset used for correction before sending the asset to Houdini" ) )
.Font( FEditorStyle::GetFontStyle( TEXT( "PropertyWindow.NormalFont" ) ) )
]
];
// Set delegate for image
ExpanderImage->SetImage(
TAttribute<const FSlateBrush*>::Create(
TAttribute<const FSlateBrush*>::FGetter::CreateLambda( [=]() {
FName ResourceName;
if ( MyParam->TransformUIExpanded[ AtIndex ] )
{
if ( ExpanderArrow->IsHovered() )
ResourceName = "TreeArrow_Expanded_Hovered";
else
ResourceName = "TreeArrow_Expanded";
}
else
{
if ( ExpanderArrow->IsHovered() )
ResourceName = "TreeArrow_Collapsed_Hovered";
else
ResourceName = "TreeArrow_Collapsed";
}
return FEditorStyle::GetBrush( ResourceName );
} ) ) );
}
// TRANSFORM
if ( InParam.TransformUIExpanded[ AtIndex ] )
{
// Position
VerticalBox->AddSlot().Padding( 0, 2 ).AutoHeight()
[
SNew( SHorizontalBox )
+SHorizontalBox::Slot()
.Padding( 1.0f )
.VAlign( VAlign_Center )
.AutoWidth()
[
SNew(STextBlock)
.Text( LOCTEXT("GeoInputTranslate", "T") )
.ToolTipText( LOCTEXT( "GeoInputTranslateTooltip", "Translate" ) )
.Font( FEditorStyle::GetFontStyle( TEXT( "PropertyWindow.NormalFont" ) ) )
]
+ SHorizontalBox::Slot().MaxWidth( HAPI_UNREAL_DESIRED_ROW_VALUE_WIDGET_WIDTH )
[
SNew( SVectorInputBox )
.bColorAxisLabels( true )
.X( TAttribute< TOptional< float > >::Create(
TAttribute< TOptional< float > >::FGetter::CreateUObject(
&InParam, &UHoudiniAssetInput::GetPositionX, AtIndex ) ) )
.Y( TAttribute< TOptional< float > >::Create(
TAttribute< TOptional< float> >::FGetter::CreateUObject(
&InParam, &UHoudiniAssetInput::GetPositionY, AtIndex ) ) )
.Z( TAttribute< TOptional< float> >::Create(
TAttribute< TOptional< float > >::FGetter::CreateUObject(
&InParam, &UHoudiniAssetInput::GetPositionZ, AtIndex ) ) )
.OnXChanged( FOnFloatValueChanged::CreateUObject(
&InParam, &UHoudiniAssetInput::SetPositionX, AtIndex ) )
.OnYChanged( FOnFloatValueChanged::CreateUObject(
&InParam, &UHoudiniAssetInput::SetPositionY, AtIndex ) )
.OnZChanged( FOnFloatValueChanged::CreateUObject(
&InParam, &UHoudiniAssetInput::SetPositionZ, AtIndex ) )
]
];
// Rotation
VerticalBox->AddSlot().Padding( 0, 2 ).AutoHeight()
[
SNew( SHorizontalBox )
+SHorizontalBox::Slot()
.Padding(1.0f)
.VAlign(VAlign_Center)
.AutoWidth()
[
SNew(STextBlock)
.Text( LOCTEXT("GeoInputRotate", "R") )
.ToolTipText( LOCTEXT( "GeoInputRotateTooltip", "Rotate" ) )
.Font( FEditorStyle::GetFontStyle( TEXT( "PropertyWindow.NormalFont" ) ) )
]
+ SHorizontalBox::Slot().MaxWidth( HAPI_UNREAL_DESIRED_ROW_VALUE_WIDGET_WIDTH )
[
SNew( SRotatorInputBox )
.AllowSpin( true )
.bColorAxisLabels( true )
.Roll( TAttribute< TOptional< float > >::Create(
TAttribute< TOptional< float > >::FGetter::CreateUObject(
&InParam, &UHoudiniAssetInput::GetRotationRoll, AtIndex ) ) )
.Pitch( TAttribute< TOptional< float> >::Create(
TAttribute< TOptional< float > >::FGetter::CreateUObject(
&InParam, &UHoudiniAssetInput::GetRotationPitch, AtIndex) ) )
.Yaw( TAttribute<TOptional< float > >::Create(
TAttribute< TOptional< float > >::FGetter::CreateUObject(
&InParam, &UHoudiniAssetInput::GetRotationYaw, AtIndex) ) )
.OnRollChanged( FOnFloatValueChanged::CreateUObject(
&InParam, &UHoudiniAssetInput::SetRotationRoll, AtIndex) )
.OnPitchChanged( FOnFloatValueChanged::CreateUObject(
&InParam, &UHoudiniAssetInput::SetRotationPitch, AtIndex) )
.OnYawChanged( FOnFloatValueChanged::CreateUObject(
&InParam, &UHoudiniAssetInput::SetRotationYaw, AtIndex) )
]
];
// Scale
VerticalBox->AddSlot().Padding( 0, 2 ).AutoHeight()
[
SNew( SHorizontalBox )
+SHorizontalBox::Slot()
.Padding( 1.0f )
.VAlign( VAlign_Center )
.AutoWidth()
[
SNew( STextBlock )
.Text( LOCTEXT( "GeoInputScale", "S" ) )
.ToolTipText( LOCTEXT( "GeoInputScaleTooltip", "Scale" ) )
.Font( FEditorStyle::GetFontStyle( TEXT( "PropertyWindow.NormalFont" ) ) )
]
+ SHorizontalBox::Slot().MaxWidth( HAPI_UNREAL_DESIRED_ROW_VALUE_WIDGET_WIDTH )
[
SNew( SVectorInputBox )
.bColorAxisLabels( true )
.X( TAttribute< TOptional< float > >::Create(
TAttribute< TOptional< float > >::FGetter::CreateUObject(
&InParam, &UHoudiniAssetInput::GetScaleX, AtIndex ) ) )
.Y( TAttribute< TOptional< float > >::Create(
TAttribute< TOptional< float> >::FGetter::CreateUObject(
&InParam, &UHoudiniAssetInput::GetScaleY, AtIndex ) ) )
.Z( TAttribute< TOptional< float> >::Create(
TAttribute< TOptional< float > >::FGetter::CreateUObject(
&InParam, &UHoudiniAssetInput::GetScaleZ, AtIndex ) ) )
.OnXChanged( FOnFloatValueChanged::CreateUObject(
&InParam, &UHoudiniAssetInput::SetScaleX, AtIndex ) )
.OnYChanged( FOnFloatValueChanged::CreateUObject(
&InParam, &UHoudiniAssetInput::SetScaleY, AtIndex ) )
.OnZChanged( FOnFloatValueChanged::CreateUObject(
&InParam, &UHoudiniAssetInput::SetScaleZ, AtIndex ) )
]
/*
+ SHorizontalBox::Slot().AutoWidth()
[
// Add a checkbox to toggle between preserving the ratio of x,y,z components of scale when a value is entered
SNew( SCheckBox )
.Style( FEditorStyle::Get(), "TransparentCheckBox" )
.ToolTipText( LOCTEXT( "PreserveScaleToolTip", "When locked, scales uniformly based on the current xyz scale values so the object maintains its shape in each direction when scaled" ) )
.OnCheckStateChanged( FOnCheckStateChanged::CreateUObject(
this, &UHoudiniAssetInput::CheckStateChanged, AtIndex ) )
.IsChecked( TAttribute< ECheckBoxState >::Create(
TAttribute<ECheckBoxState>::FGetter::CreateUObject(
this, &UHoudiniAssetInput::IsChecked, AtIndex ) ) )
[
SNew( SImage )
.Image( TAttribute<const FSlateBrush*>::Create(
TAttribute<const FSlateBrush*>::FGetter::CreateUObject(
this, &UHoudiniAssetInput::GetPreserveScaleRatioImage, AtIndex ) ) )
.ColorAndOpacity( FSlateColor::UseForeground() )
]
]
*/
];
}
}
/** Create a single skeleton widget for the given input object */
void FHoudiniParameterDetails::Helper_CreateSkeletonWidget(
UHoudiniAssetInput& InParam, int32 AtIndex, UObject* InputObject,
TSharedPtr< FAssetThumbnailPool > AssetThumbnailPool, TSharedRef< SVerticalBox > VerticalBox )
{
TWeakObjectPtr<UHoudiniAssetInput> MyParam( &InParam );
// Create thumbnail for this skeleton mesh.
TSharedPtr< FAssetThumbnail > SkeletalMeshThumbnail = MakeShareable(
new FAssetThumbnail( InputObject, 64, 64, AssetThumbnailPool ) );
TSharedPtr< SHorizontalBox > HorizontalBox = NULL;
// Drop Target: Skeletal Mesh
VerticalBox->AddSlot().Padding( 0, 2 ).AutoHeight()
[
SNew( SAssetDropTarget )
.OnIsAssetAcceptableForDrop( SAssetDropTarget::FIsAssetAcceptableForDrop::CreateLambda(
[] ( const UObject* InObject )
{
return InObject && InObject->IsA< USkeletalMesh >();
}
) )
.OnAssetDropped( SAssetDropTarget::FOnAssetDropped::CreateUObject(
&InParam, &UHoudiniAssetInput::OnSkeletalMeshDropped, AtIndex ) )
[
SAssignNew(HorizontalBox, SHorizontalBox)
]
];
// Thumbnail : Skeletal Mesh
FText ParameterLabelText = FText::FromString( InParam.GetParameterLabel() );
//FText ParameterTooltip = GetParameterTooltip( &InParam, true );
TSharedPtr< SBorder > SkeletalMeshThumbnailBorder;
HorizontalBox->AddSlot().Padding(0.0f, 0.0f, 2.0f, 0.0f).AutoWidth()
[
SAssignNew( SkeletalMeshThumbnailBorder, SBorder )
.Padding(5.0f)
.OnMouseDoubleClick(FPointerEventHandler::CreateUObject(&InParam, &UHoudiniAssetInput::OnThumbnailDoubleClick, AtIndex))
[
SNew(SBox)
.WidthOverride(64)
.HeightOverride(64)
.ToolTipText(ParameterLabelText)
[
SkeletalMeshThumbnail->MakeThumbnailWidget()
]
]
];
SkeletalMeshThumbnailBorder->SetBorderImage( TAttribute< const FSlateBrush * >::Create(
TAttribute< const FSlateBrush * >::FGetter::CreateLambda( [ SkeletalMeshThumbnailBorder ]()
{
if ( SkeletalMeshThumbnailBorder.IsValid() && SkeletalMeshThumbnailBorder->IsHovered() )
return FEditorStyle::GetBrush( "PropertyEditor.AssetThumbnailLight" );
else
return FEditorStyle::GetBrush( "PropertyEditor.AssetThumbnailShadow" );
} ) ) );
FText MeshNameText = FText::GetEmpty();
if ( InputObject )
MeshNameText = FText::FromString( InputObject->GetName() );
// ComboBox : Skeletal Mesh
TSharedPtr< SComboButton > SkeletalMeshComboButton;
TSharedPtr< SHorizontalBox > ButtonBox;
HorizontalBox->AddSlot()
.FillWidth( 1.0f )
.Padding( 0.0f, 4.0f, 4.0f, 4.0f )
.VAlign( VAlign_Center )
[
SNew( SVerticalBox )
+ SVerticalBox::Slot()
.HAlign( HAlign_Fill )
[
SAssignNew( ButtonBox, SHorizontalBox )
+ SHorizontalBox::Slot()
[
SAssignNew(SkeletalMeshComboButton, SComboButton )
.ButtonStyle( FEditorStyle::Get(), "PropertyEditor.AssetComboStyle" )
.ForegroundColor( FEditorStyle::GetColor( "PropertyEditor.AssetName.ColorAndOpacity" ) )
.ContentPadding( 2.0f )
.ButtonContent()
[
SNew( STextBlock )
.TextStyle( FEditorStyle::Get(), "PropertyEditor.AssetClass" )
.Font( FEditorStyle::GetFontStyle( FName( TEXT( "PropertyWindow.NormalFont" ) ) ) )
.Text( MeshNameText )
]
]
]
];
SkeletalMeshComboButton->SetOnGetMenuContent( FOnGetContent::CreateLambda(
[ MyParam, AtIndex, SkeletalMeshComboButton ]()
{
TArray< const UClass * > AllowedClasses;
AllowedClasses.Add(USkeletalMesh::StaticClass());
TArray< UFactory * > NewAssetFactories;
return PropertyCustomizationHelpers::MakeAssetPickerWithMenu(
FAssetData( MyParam->GetInputObject( AtIndex ) ),
true,
AllowedClasses,
NewAssetFactories,
FOnShouldFilterAsset(),
FOnAssetSelected::CreateLambda(
[ MyParam, AtIndex, SkeletalMeshComboButton]( const FAssetData & AssetData )
{
if (SkeletalMeshComboButton.IsValid())
{
SkeletalMeshComboButton->SetIsOpen(false);
UObject * Object = AssetData.GetAsset();
MyParam->OnSkeletalMeshDropped(Object, AtIndex);
}
} ),
FSimpleDelegate::CreateLambda( [](){})
);
} ) );
// Create tooltip.
FFormatNamedArguments Args;
Args.Add( TEXT("Asset"), MeshNameText );
FText SkeletalMeshTooltip = FText::Format(
LOCTEXT("BrowseToSpecificAssetInContentBrowser",
"Browse to '{Asset}' in Content Browser"), Args);
// Button : Browse Skeletal Mesh
ButtonBox->AddSlot()
.AutoWidth()
.Padding( 2.0f, 0.0f )
.VAlign( VAlign_Center )
[
PropertyCustomizationHelpers::MakeBrowseButton(
FSimpleDelegate::CreateUObject( &InParam, &UHoudiniAssetInput::OnStaticMeshBrowse, AtIndex ),
TAttribute< FText >( SkeletalMeshTooltip ) )
];
// ButtonBox : Reset
ButtonBox->AddSlot()
.AutoWidth()
.Padding( 2.0f, 0.0f )
.VAlign( VAlign_Center )
[
SNew( SButton )
.ToolTipText( LOCTEXT( "ResetToBase", "Reset to default skeletal mesh" ) )
.ButtonStyle( FEditorStyle::Get(), "NoBorder" )
.ContentPadding( 0 )
.Visibility( EVisibility::Visible )
.OnClicked( FOnClicked::CreateUObject( &InParam, &UHoudiniAssetInput::OnResetSkeletalMeshClicked, AtIndex ) )
[
SNew( SImage )
.Image( FEditorStyle::GetBrush( "PropertyWindow.DiffersFromDefault" ) )
]
];
ButtonBox->AddSlot()
.Padding( 1.0f )
.VAlign( VAlign_Center )
.AutoWidth()
[
PropertyCustomizationHelpers::MakeInsertDeleteDuplicateButton(
FExecuteAction::CreateLambda( [ MyParam, AtIndex ](){ MyParam->OnInsertGeo( AtIndex ); } ),
FExecuteAction::CreateLambda( [ MyParam, AtIndex ](){ MyParam->OnDeleteGeo( AtIndex ); } ),
FExecuteAction::CreateLambda( [ MyParam, AtIndex ](){ MyParam->OnDuplicateGeo( AtIndex ); } ) )
];
/*
// TRANSFORM
{
TSharedPtr<SButton> ExpanderArrow;
TSharedPtr<SImage> ExpanderImage;
VerticalBox->AddSlot().Padding( 0, 2 ).AutoHeight()
[
SNew( SHorizontalBox )
+ SHorizontalBox::Slot()
.Padding( 1.0f )
.VAlign( VAlign_Center )
.AutoWidth()
[
SAssignNew( ExpanderArrow, SButton )
.ButtonStyle( FEditorStyle::Get(), "NoBorder" )
.ClickMethod( EButtonClickMethod::MouseDown )
.Visibility( EVisibility::Visible )
.OnClicked( FOnClicked::CreateUObject( &InParam, &UHoudiniAssetInput::OnExpandInputTransform, AtIndex ) )
[
SAssignNew( ExpanderImage, SImage )
.ColorAndOpacity( FSlateColor::UseForeground() )
]
]
+ SHorizontalBox::Slot()
.Padding( 1.0f )
.VAlign( VAlign_Center )
.AutoWidth()
[
SNew( STextBlock )
.Text( LOCTEXT("GeoInputTransform", "Transform Offset" ) )
.ToolTipText( LOCTEXT( "GeoInputTransformTooltip", "Transform offset used for correction before sending the asset to Houdini" ) )
.Font( FEditorStyle::GetFontStyle( TEXT( "PropertyWindow.NormalFont" ) ) )
]
];
// Set delegate for image
ExpanderImage->SetImage( TAttribute<const FSlateBrush*>::Create(
TAttribute<const FSlateBrush*>::FGetter::CreateLambda( [=]()
{
FName ResourceName;
if ( MyParam->TransformUIExpanded[ AtIndex ] )
{
if ( ExpanderArrow->IsHovered() )
ResourceName = "TreeArrow_Expanded_Hovered";
else
ResourceName = "TreeArrow_Expanded";
}
else
{
if ( ExpanderArrow->IsHovered() )
ResourceName = "TreeArrow_Collapsed_Hovered";
else
ResourceName = "TreeArrow_Collapsed";
}
return FEditorStyle::GetBrush( ResourceName );
} ) ) );
}
if ( InParam.TransformUIExpanded[ AtIndex ] )
{
// Position
VerticalBox->AddSlot().Padding( 0, 2 ).AutoHeight()
[
SNew( SHorizontalBox )
+ SHorizontalBox::Slot()
.Padding( 1.0f )
.VAlign( VAlign_Center )
.AutoWidth()
[
SNew( STextBlock )
.Text( LOCTEXT( "GeoInputTranslate", "T" ) )
.ToolTipText( LOCTEXT( "GeoInputTranslateTooltip", "Translate" ) )
.Font( FEditorStyle::GetFontStyle( TEXT( "PropertyWindow.NormalFont" ) ) )
]
+ SHorizontalBox::Slot().MaxWidth( HAPI_UNREAL_DESIRED_ROW_VALUE_WIDGET_WIDTH )
[
SNew( SVectorInputBox )
.bColorAxisLabels( true )
.X( TAttribute< TOptional< float > >::Create(
TAttribute< TOptional< float > >::FGetter::CreateUObject( &InParam, &UHoudiniAssetInput::GetPositionX, AtIndex ) ) )
.Y(TAttribute< TOptional< float > >::Create(
TAttribute< TOptional< float > >::FGetter::CreateUObject( &InParam, &UHoudiniAssetInput::GetPositionY, AtIndex ) ) )
.Z(TAttribute< TOptional< float > >::Create(
TAttribute< TOptional< float > >::FGetter::CreateUObject( &InParam, &UHoudiniAssetInput::GetPositionZ, AtIndex ) ) )
.OnXChanged( FOnFloatValueChanged::CreateUObject( &InParam, &UHoudiniAssetInput::SetPositionX, AtIndex ) )
.OnYChanged(FOnFloatValueChanged::CreateUObject( &InParam, &UHoudiniAssetInput::SetPositionY, AtIndex ) )
.OnZChanged(FOnFloatValueChanged::CreateUObject( &InParam, &UHoudiniAssetInput::SetPositionZ, AtIndex ) )
]
];
// Rotation
VerticalBox->AddSlot().Padding( 0, 2 ).AutoHeight()
[
SNew( SHorizontalBox )
+ SHorizontalBox::Slot()
.Padding( 1.0f )
.VAlign( VAlign_Center )
.AutoWidth()
[
SNew( STextBlock )
.Text( LOCTEXT( "GeoInputRotate", "R" ) )
.ToolTipText(LOCTEXT("GeoInputRotateTooltip", "Rotate") )
.Font(FEditorStyle::GetFontStyle(TEXT("PropertyWindow.NormalFont")))
]
+ SHorizontalBox::Slot().MaxWidth(HAPI_UNREAL_DESIRED_ROW_VALUE_WIDGET_WIDTH)
[
SNew(SRotatorInputBox)
.AllowSpin(true)
.bColorAxisLabels(true)
.Roll(TAttribute< TOptional< float > >::Create(
TAttribute< TOptional< float > >::FGetter::CreateUObject(
&InParam, &UHoudiniAssetInput::GetRotationRoll, AtIndex)))
.Pitch(TAttribute< TOptional< float> >::Create(
TAttribute< TOptional< float > >::FGetter::CreateUObject(
&InParam, &UHoudiniAssetInput::GetRotationPitch, AtIndex)))
.Yaw(TAttribute<TOptional< float > >::Create(
TAttribute< TOptional< float > >::FGetter::CreateUObject(
&InParam, &UHoudiniAssetInput::GetRotationYaw, AtIndex)))
.OnRollChanged(FOnFloatValueChanged::CreateUObject(
&InParam, &UHoudiniAssetInput::SetRotationRoll, AtIndex))
.OnPitchChanged(FOnFloatValueChanged::CreateUObject(
&InParam, &UHoudiniAssetInput::SetRotationPitch, AtIndex))
.OnYawChanged(FOnFloatValueChanged::CreateUObject(
&InParam, &UHoudiniAssetInput::SetRotationYaw, AtIndex))
]
];
// Scale
VerticalBox->AddSlot().Padding(0, 2).AutoHeight()
[
SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
.Padding(1.0f)
.VAlign(VAlign_Center)
.AutoWidth()
[
SNew(STextBlock)
.Text(LOCTEXT("GeoInputScale", "S"))
.ToolTipText(LOCTEXT("GeoInputScaleTooltip", "Scale"))
.Font(FEditorStyle::GetFontStyle(TEXT("PropertyWindow.NormalFont")))
]
+ SHorizontalBox::Slot().MaxWidth(HAPI_UNREAL_DESIRED_ROW_VALUE_WIDGET_WIDTH)
[
SNew(SVectorInputBox)
.bColorAxisLabels(true)
.X(TAttribute< TOptional< float > >::Create(
TAttribute< TOptional< float > >::FGetter::CreateUObject(
&InParam, &UHoudiniAssetInput::GetScaleX, AtIndex)))
.Y(TAttribute< TOptional< float > >::Create(
TAttribute< TOptional< float> >::FGetter::CreateUObject(
&InParam, &UHoudiniAssetInput::GetScaleY, AtIndex)))
.Z(TAttribute< TOptional< float> >::Create(
TAttribute< TOptional< float > >::FGetter::CreateUObject(
&InParam, &UHoudiniAssetInput::GetScaleZ, AtIndex)))
.OnXChanged(FOnFloatValueChanged::CreateUObject(
&InParam, &UHoudiniAssetInput::SetScaleX, AtIndex))
.OnYChanged(FOnFloatValueChanged::CreateUObject(
&InParam, &UHoudiniAssetInput::SetScaleY, AtIndex))
.OnZChanged(FOnFloatValueChanged::CreateUObject(
&InParam, &UHoudiniAssetInput::SetScaleZ, AtIndex))
]
];
}
*/
}
FReply
FHoudiniParameterDetails::Helper_OnButtonClickSelectActors(
TWeakObjectPtr<class UHoudiniAssetInput> InParam,
FName DetailsPanelName)
{
return Helper_OnButtonClickSelectActors( InParam, DetailsPanelName, false );
}
FReply
FHoudiniParameterDetails::Helper_OnButtonClickUseSelectionAsBoundSelector(
TWeakObjectPtr<class UHoudiniAssetInput> InParam,
FName DetailsPanelName )
{
return Helper_OnButtonClickSelectActors(InParam, DetailsPanelName, true);
}
FReply
FHoudiniParameterDetails::Helper_OnButtonClickSelectActors(
TWeakObjectPtr<class UHoudiniAssetInput> InParam,
FName DetailsPanelName,
const bool& bUseWorldInAsWorldSelector )
{
if ( !InParam.IsValid() )
return FReply::Handled();
// There's no undo operation for button.
FPropertyEditorModule & PropertyModule =
FModuleManager::Get().GetModuleChecked< FPropertyEditorModule >( "PropertyEditor" );
// Locate the details panel.
TSharedPtr< IDetailsView > DetailsView = PropertyModule.FindDetailView( DetailsPanelName );
if ( !DetailsView.IsValid() )
return FReply::Handled();
class SLocalDetailsView : public SDetailsViewBase
{
public:
void LockDetailsView() { SDetailsViewBase::bIsLocked = true; }
void UnlockDetailsView() { SDetailsViewBase::bIsLocked = false; }
};
auto * LocalDetailsView = static_cast< SLocalDetailsView * >( DetailsView.Get() );
if ( !DetailsView->IsLocked() )
{
LocalDetailsView->LockDetailsView();
check( DetailsView->IsLocked() );
// Force refresh of details view.
InParam->OnParamStateChanged();
// Select the previously chosen input Actors from the World Outliner.
GEditor->SelectNone( false, true );
for ( auto & OutlinerMesh : InParam->InputOutlinerMeshArray )
{
if ( OutlinerMesh.ActorPtr.IsValid() )
GEditor->SelectActor( OutlinerMesh.ActorPtr.Get(), true, true );
}
return FReply::Handled();
}
if ( !GEditor || !GEditor->GetSelectedObjects() )
return FReply::Handled();
// If details panel is locked, locate selected actors and check if this component belongs to one of them.
FScopedTransaction Transaction(
TEXT( HOUDINI_MODULE_RUNTIME ),
LOCTEXT( "HoudiniInputChange", "Houdini World Outliner Input Change" ),
InParam->PrimaryObject );
InParam->Modify();
InParam->bStaticMeshChanged = true;
// Delete all assets and reset the array.
// TODO: Make this process a little more efficient.
InParam->DisconnectAndDestroyInputAsset();
InParam->InputOutlinerMeshArray.Empty();
USelection * SelectedActors = GEditor->GetSelectedActors();
if ( !SelectedActors )
return FReply::Handled();
if ( bUseWorldInAsWorldSelector )
{
// Build an array of the current selection's bounds
TArray<FBox> AllBBox;
for (FSelectionIterator It(*SelectedActors); It; ++It)
{
AActor * CurrentActor = Cast< AActor >(*It);
if (!CurrentActor || CurrentActor->IsPendingKill())
continue;
AllBBox.Add(CurrentActor->GetComponentsBoundingBox(true));
}
UWorld* editorWorld = GEditor->GetEditorWorldContext().World();
for (TActorIterator<AActor> ActorItr(editorWorld); ActorItr; ++ActorItr)
{
AActor *CurrentActor = *ActorItr;
if (!CurrentActor || CurrentActor->IsPendingKill())
continue;
// Check that actor is currently not selected
if (CurrentActor->IsSelected())
continue;
// Ignore the SkySpheres?
FString ClassName = CurrentActor->GetClass() ? CurrentActor->GetClass()->GetName() : FString();
if (ClassName.Contains("BP_Sky_Sphere"))
continue;
// Don't allow selection of ourselves. Bad things happen if we do.
if ( InParam->GetHoudiniAssetComponent() && (CurrentActor == InParam->GetHoudiniAssetComponent()->GetOwner()) )
continue;
FBox ActorBounds = CurrentActor->GetComponentsBoundingBox(true);
for (auto InBounds : AllBBox)
{
// Check if both actor's bounds intersects
if (!ActorBounds.Intersect(InBounds))
continue;
// Current actors intersect with our selection's bounds, update the input with it
InParam->UpdateInputOulinerArrayFromActor(CurrentActor, false);
break;
}
}
}
else
{
// If the builder brush is selected, first deselect it.
for ( FSelectionIterator It(*SelectedActors); It; ++It )
{
AActor * Actor = Cast< AActor >(*It);
if (!Actor)
continue;
// Don't allow selection of ourselves. Bad things happen if we do.
if (InParam->GetHoudiniAssetComponent() && (Actor == InParam->GetHoudiniAssetComponent()->GetOwner()))
continue;
InParam->UpdateInputOulinerArrayFromActor(Actor, false);
}
}
InParam->MarkChanged();
AActor* HoudiniAssetActor = InParam->GetHoudiniAssetComponent()->GetOwner();
if ( DetailsView->IsLocked() )
{
LocalDetailsView->UnlockDetailsView();
check( !DetailsView->IsLocked() );
TArray< UObject * > DummySelectedActors;
DummySelectedActors.Add( HoudiniAssetActor );
// Reset selected actor to itself, force refresh and override the lock.
DetailsView->SetObjects( DummySelectedActors, true, true );
}
// Reselect the Asset Actor. If we don't do this, our Asset parameters will stop
// refreshing and the user will be very confused. It is also resetting the state
// of the selection before the input actor selection process was started.
GEditor->SelectNone( false, true );
GEditor->SelectActor( HoudiniAssetActor, true, true );
// Update parameter layout.
InParam->OnParamStateChanged();
// Start or stop the tick timer to check if the selected Actors have been transformed.
if ( InParam->InputOutlinerMeshArray.Num() > 0 )
InParam->StartWorldOutlinerTicking();
else if ( InParam->InputOutlinerMeshArray.Num() <= 0 )
InParam->StopWorldOutlinerTicking();
return FReply::Handled();
}
void
FHoudiniParameterDetails::CreateWidgetInput( IDetailCategoryBuilder & LocalDetailCategoryBuilder, class UHoudiniAssetInput& InParam )
{
TWeakObjectPtr<UHoudiniAssetInput> MyParam( &InParam );
// Get thumbnail pool for this builder.
IDetailLayoutBuilder & DetailLayoutBuilder = LocalDetailCategoryBuilder.GetParentLayout();
TSharedPtr< FAssetThumbnailPool > AssetThumbnailPool = DetailLayoutBuilder.GetThumbnailPool();
FDetailWidgetRow & Row = LocalDetailCategoryBuilder.AddCustomRow( FText::GetEmpty() );
FText ParameterLabelText = FText::FromString( InParam.GetParameterLabel() );
FText ParameterTooltip = GetParameterTooltip( &InParam );
Row.NameWidget.Widget =
SNew( STextBlock )
.Text( ParameterLabelText )
.ToolTipText( ParameterTooltip )
.Font( FEditorStyle::GetFontStyle( TEXT( "PropertyWindow.NormalFont" ) ) );
TSharedRef< SVerticalBox > VerticalBox = SNew( SVerticalBox );
if ( InParam.StringChoiceLabels.Num() > 0 )
{
// ComboBox : Input Type
TSharedPtr< SComboBox< TSharedPtr< FString > > > ComboBoxInputType;
VerticalBox->AddSlot().Padding(2, 2, 5, 2)
[
//SNew(SComboBox<TSharedPtr< FString > >)
SAssignNew( ComboBoxInputType, SComboBox< TSharedPtr< FString > > )
.OptionsSource( &InParam.StringChoiceLabels )
.InitiallySelectedItem( InParam.StringChoiceLabels[ InParam.ChoiceIndex ] )
.OnGenerateWidget( SComboBox< TSharedPtr< FString > >::FOnGenerateWidget::CreateLambda(
[]( TSharedPtr< FString > ChoiceEntry ) {
FText ChoiceEntryText = FText::FromString( *ChoiceEntry );
return SNew( STextBlock )
.Text( ChoiceEntryText )
.ToolTipText( ChoiceEntryText )
.Font( FEditorStyle::GetFontStyle( TEXT( "PropertyWindow.NormalFont" ) ) );
}))
.OnSelectionChanged( SComboBox< TSharedPtr< FString > >::FOnSelectionChanged::CreateLambda(
[=]( TSharedPtr< FString > NewChoice, ESelectInfo::Type SelectType ) {
if ( !NewChoice.IsValid() || !MyParam.IsValid() )
return;
MyParam->OnChoiceChange( NewChoice );
}))
[
SNew( STextBlock )
.Text( TAttribute< FText >::Create( TAttribute< FText >::FGetter::CreateUObject(
&InParam, &UHoudiniAssetInput::HandleChoiceContentText ) ) )
.Font( FEditorStyle::GetFontStyle( TEXT( "PropertyWindow.NormalFont" ) ) )
]
];
//ComboBoxInputType->SetSelectedItem( InParam.StringChoiceLabels[ InParam.ChoiceIndex ] );
}
// Checkbox : Keep World Transform
{
TSharedPtr< SCheckBox > CheckBoxTranformType;
VerticalBox->AddSlot().Padding(2, 2, 5, 2).AutoHeight()
[
SAssignNew(CheckBoxTranformType, SCheckBox)
.Content()
[
SNew(STextBlock)
.Text(LOCTEXT("KeepWorldTransformCheckbox", "Keep World Transform"))
.ToolTipText(LOCTEXT("KeepWorldTransformCheckboxTip", "Set this Input's object_merge Transform Type to INTO_THIS_OBJECT. If unchecked, it will be set to NONE."))
.Font(FEditorStyle::GetFontStyle(TEXT("PropertyWindow.NormalFont")))
]
.IsChecked(TAttribute< ECheckBoxState >::Create(
TAttribute< ECheckBoxState >::FGetter::CreateUObject(
&InParam, &UHoudiniAssetInput::IsCheckedKeepWorldTransform)))
.OnCheckStateChanged(FOnCheckStateChanged::CreateUObject(
&InParam, &UHoudiniAssetInput::CheckStateChangedKeepWorldTransform))
];
// the checkbox is read only for geo inputs
if ( InParam.ChoiceIndex == EHoudiniAssetInputType::GeometryInput )
CheckBoxTranformType->SetEnabled( false );
// Checkbox is read only if the input is an object-path parameter
//if ( bIsObjectPathParameter )
// CheckBoxTranformType->SetEnabled(false);
}
// Checkbox Pack before merging
if ( InParam.ChoiceIndex == EHoudiniAssetInputType::GeometryInput
|| InParam.ChoiceIndex == EHoudiniAssetInputType::WorldInput )
{
TSharedPtr< SCheckBox > CheckBoxPackBeforeMerge;
VerticalBox->AddSlot().Padding( 2, 2, 5, 2 ).AutoHeight()
[
SAssignNew( CheckBoxPackBeforeMerge, SCheckBox )
.Content()
[
SNew( STextBlock )
.Text( LOCTEXT( "PackBeforeMergeCheckbox", "Pack Geometry before merging" ) )
.ToolTipText( LOCTEXT( "PackBeforeMergeCheckboxTip", "Pack each separate piece of geometry before merging them into the input." ) )
.Font( FEditorStyle::GetFontStyle( TEXT( "PropertyWindow.NormalFont" ) ) )
]
.IsChecked( TAttribute< ECheckBoxState >::Create(
TAttribute< ECheckBoxState >::FGetter::CreateUObject(
&InParam, &UHoudiniAssetInput::IsCheckedPackBeforeMerge ) ) )
.OnCheckStateChanged( FOnCheckStateChanged::CreateUObject(
&InParam, &UHoudiniAssetInput::CheckStateChangedPackBeforeMerge ) )
];
}
// Checkboxes Export LODs and Export Sockets
if ( InParam.ChoiceIndex == EHoudiniAssetInputType::GeometryInput
|| InParam.ChoiceIndex == EHoudiniAssetInputType::WorldInput )
{
TSharedPtr< SCheckBox > CheckBoxExportAllLODs;
TSharedPtr< SCheckBox > CheckBoxExportSockets;
VerticalBox->AddSlot().Padding( 2, 2, 5, 2 ).AutoHeight()
[
SNew( SHorizontalBox )
+ SHorizontalBox::Slot()
.Padding( 1.0f )
.VAlign( VAlign_Center )
.AutoWidth()
[
SAssignNew( CheckBoxExportAllLODs, SCheckBox )
.Content()
[
SNew( STextBlock )
.Text( LOCTEXT( "ExportAllLOD", "Export LODs" ) )
.ToolTipText( LOCTEXT( "ExportAllLODCheckboxTip", "If enabled, all LOD Meshes in this static mesh will be sent to Houdini." ) )
.Font( FEditorStyle::GetFontStyle( TEXT( "PropertyWindow.NormalFont" ) ) )
]
.IsChecked( TAttribute< ECheckBoxState >::Create(
TAttribute< ECheckBoxState >::FGetter::CreateUObject(
&InParam, &UHoudiniAssetInput::IsCheckedExportAllLODs ) ) )
.OnCheckStateChanged( FOnCheckStateChanged::CreateUObject(
&InParam, &UHoudiniAssetInput::CheckStateChangedExportAllLODs ) )
]
+ SHorizontalBox::Slot()
.Padding( 1.0f )
.VAlign( VAlign_Center )
.AutoWidth()
[
SAssignNew( CheckBoxExportSockets, SCheckBox )
.Content()
[
SNew( STextBlock )
.Text( LOCTEXT( "ExportSockets", "Export Sockets" ) )
.ToolTipText( LOCTEXT( "ExportSocketsTip", "If enabled, all Mesh Sockets in this static mesh will be sent to Houdini." ) )
.Font( FEditorStyle::GetFontStyle( TEXT( "PropertyWindow.NormalFont" ) ) )
]
.IsChecked( TAttribute< ECheckBoxState >::Create(
TAttribute< ECheckBoxState >::FGetter::CreateUObject(
&InParam, &UHoudiniAssetInput::IsCheckedExportSockets ) ) )
.OnCheckStateChanged( FOnCheckStateChanged::CreateUObject(
&InParam, &UHoudiniAssetInput::CheckStateChangedExportSockets ) )
]
];
}
if ( InParam.ChoiceIndex == EHoudiniAssetInputType::GeometryInput )
{
const int32 NumInputs = InParam.InputObjects.Num();
VerticalBox->AddSlot().Padding( 2, 2, 5, 2 ).AutoHeight()
[
SNew( SHorizontalBox )
+ SHorizontalBox::Slot()
.Padding( 1.0f )
.VAlign( VAlign_Center )
.AutoWidth()
[
SNew( STextBlock )
.Text( FText::Format( LOCTEXT( "NumArrayItemsFmt", "{0} elements" ), FText::AsNumber( NumInputs ) ) )
.Font( FEditorStyle::GetFontStyle( TEXT( "PropertyWindow.NormalFont" ) ) )
]
+ SHorizontalBox::Slot()
.Padding( 1.0f )
.VAlign( VAlign_Center )
.AutoWidth()
[
PropertyCustomizationHelpers::MakeAddButton( FSimpleDelegate::CreateUObject( &InParam, &UHoudiniAssetInput::OnAddToInputObjects ), LOCTEXT( "AddInput", "Adds a Geometry Input" ), true )
]
+ SHorizontalBox::Slot()
.Padding( 1.0f )
.VAlign( VAlign_Center )
.AutoWidth()
[
PropertyCustomizationHelpers::MakeEmptyButton( FSimpleDelegate::CreateUObject( &InParam, &UHoudiniAssetInput::OnEmptyInputObjects ), LOCTEXT( "EmptyInputs", "Removes All Inputs" ), true )
]
];
for ( int32 Ix = 0; Ix < NumInputs; Ix++ )
{
UObject* InputObject = InParam.GetInputObject( Ix );
Helper_CreateGeometryWidget( InParam, Ix, InputObject, AssetThumbnailPool, VerticalBox );
}
}
else if ( InParam.ChoiceIndex == EHoudiniAssetInputType::AssetInput )
{
// ActorPicker : Houdini Asset
FMenuBuilder MenuBuilder = Helper_CreateCustomActorPickerWidget( InParam, LOCTEXT( "AssetInputSelectableActors", "Houdini Asset Actors" ), true );
VerticalBox->AddSlot().Padding(2, 2, 5, 2).AutoHeight()
[
MenuBuilder.MakeWidget()
];
}
else if ( InParam.ChoiceIndex == EHoudiniAssetInputType::CurveInput )
{
// Go through all input curve parameters and build their widgets recursively.
for ( TMap< FString, UHoudiniAssetParameter * >::TIterator
IterParams( InParam.InputCurveParameters ); IterParams; ++IterParams )
{
// Note: Only choice and toggle supported atm
if ( UHoudiniAssetParameter * HoudiniAssetParameter = IterParams.Value() )
FHoudiniParameterDetails::CreateWidget( VerticalBox, HoudiniAssetParameter );
}
}
else if ( InParam.ChoiceIndex == EHoudiniAssetInputType::LandscapeInput )
{
// CheckBox : Update Input Landscape Data
{
TSharedPtr< SCheckBox > CheckBoxUpdateInput;
VerticalBox->AddSlot().Padding(2, 2, 5, 2).AutoHeight()
[
SAssignNew( CheckBoxUpdateInput, SCheckBox )
.Content()
[
SNew(STextBlock)
.Text(LOCTEXT("LandscapeUpdateInputCheckbox", "Update Input Landscape Data"))
.ToolTipText(LOCTEXT("LandscapeSelectedTooltip", "If enabled, the input landscape's data will be updated instead of creating a new Landscape Actor."))
.Font(FEditorStyle::GetFontStyle(TEXT("PropertyWindow.NormalFont")))
]
.IsChecked(TAttribute< ECheckBoxState >::Create(
TAttribute< ECheckBoxState >::FGetter::CreateUObject(
&InParam, &UHoudiniAssetInput::IsCheckedUpdateInputLandscape ) ) )
.OnCheckStateChanged(FOnCheckStateChanged::CreateUObject(
&InParam, &UHoudiniAssetInput::CheckStateChangedUpdateInputLandscape ) )
];
// Only enable if we're exporting as HF
CheckBoxUpdateInput->SetEnabled(static_cast<bool>(InParam.bLandscapeExportAsHeightfield));
}
// ActorPicker : Landscape
FMenuBuilder MenuBuilder = Helper_CreateCustomActorPickerWidget( InParam, LOCTEXT( "LandscapeInputSelectableActors", "Landscapes" ), true );
VerticalBox->AddSlot().Padding(2, 2, 5, 2).AutoHeight()
[
MenuBuilder.MakeWidget()
];
// Checkboxes : Export Landscape As
// Heightfield Mesh Points
{
// Label
VerticalBox->AddSlot().Padding(2, 2, 5, 2).AutoHeight()
[
SNew(STextBlock)
.Text(LOCTEXT("LandscapeExportAs", "Export Landscape As"))
.ToolTipText(LOCTEXT("LandscapeExportAsTooltip", "Choose the type of data you want the landscape to be exported to:\n * Heightfield\n * Mesh\n * Points"))
.Font(FEditorStyle::GetFontStyle(TEXT("PropertyWindow.NormalFont")))
];
//
TSharedPtr<SUniformGridPanel> ButtonOptionsPanel;
VerticalBox->AddSlot().Padding(5, 2, 5, 2).AutoHeight()
[
SAssignNew( ButtonOptionsPanel, SUniformGridPanel )
];
// Heightfield
FText HeightfieldTooltip = LOCTEXT("LandscapeExportAsHeightfieldTooltip", "If enabled, the landscape will be exported to Houdini as a heighfield.");
ButtonOptionsPanel->AddSlot(0, 0)
[
SNew(SCheckBox)
.Style(FEditorStyle::Get(), "Property.ToggleButton.Start")
.IsChecked( TAttribute< ECheckBoxState >::Create(
TAttribute< ECheckBoxState >::FGetter::CreateUObject(
&InParam, &UHoudiniAssetInput::IsCheckedExportAsHeightfield ) ) )
.OnCheckStateChanged( FOnCheckStateChanged::CreateUObject(
&InParam, &UHoudiniAssetInput::CheckStateChangedExportAsHeightfield ) )
.ToolTipText( HeightfieldTooltip )
[
SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
.AutoWidth()
.VAlign(VAlign_Center)
.Padding(2, 2)
[
SNew(SImage)
.Image(FEditorStyle::GetBrush("ClassIcon.LandscapeComponent"))
]
+ SHorizontalBox::Slot()
.FillWidth(1.0f)
.VAlign(VAlign_Center)
.HAlign(HAlign_Center)
.Padding(2, 2)
[
SNew(STextBlock)
.Text( LOCTEXT( "LandscapeExportAsHeightfieldCheckbox", "Heightfield" ) )
.ToolTipText( HeightfieldTooltip )
.Font( IDetailLayoutBuilder::GetDetailFont() )
]
]
];
// Mesh
FText MeshTooltip = LOCTEXT("LandscapeExportAsHeightfieldTooltip", "If enabled, the landscape will be exported to Houdini as a heighfield.");
ButtonOptionsPanel->AddSlot(1, 0)
[
SNew(SCheckBox)
.Style(FEditorStyle::Get(), "Property.ToggleButton.Middle")
.IsChecked( TAttribute< ECheckBoxState >::Create(
TAttribute< ECheckBoxState >::FGetter::CreateUObject(
&InParam, &UHoudiniAssetInput::IsCheckedExportAsMesh ) ) )
.OnCheckStateChanged( FOnCheckStateChanged::CreateUObject(
&InParam, &UHoudiniAssetInput::CheckStateChangedExportAsMesh ) )
.ToolTipText( MeshTooltip )
[
SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
.AutoWidth()
.VAlign(VAlign_Center)
.Padding(2, 2)
[
SNew(SImage)
.Image(FEditorStyle::GetBrush( "ClassIcon.StaticMeshComponent" ) )
]
+ SHorizontalBox::Slot()
.FillWidth(1.0f)
.VAlign(VAlign_Center)
.HAlign(HAlign_Center)
.Padding(2, 2)
[
SNew( STextBlock )
.Text( LOCTEXT( "LandscapeExportAsMeshCheckbox", "Mesh" ) )
.ToolTipText( MeshTooltip )
.Font( IDetailLayoutBuilder::GetDetailFont() )
]
]
];
// Points
FText PointsTooltip = LOCTEXT( "LandscapeExportAsPointsTooltip", "If enabled, the landscape will be exported to Houdini as points." );
ButtonOptionsPanel->AddSlot(2, 0)
[
SNew(SCheckBox)
.Style(FEditorStyle::Get(), "Property.ToggleButton.End")
.IsChecked( TAttribute< ECheckBoxState >::Create(
TAttribute< ECheckBoxState >::FGetter::CreateUObject(
&InParam, &UHoudiniAssetInput::IsCheckedExportAsPoints ) ) )
.OnCheckStateChanged( FOnCheckStateChanged::CreateUObject(
&InParam, &UHoudiniAssetInput::CheckStateChangedExportAsPoints ) )
.ToolTipText( PointsTooltip )
[
SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
.AutoWidth()
.VAlign(VAlign_Center)
.Padding(2, 2)
[
SNew(SImage)
.Image(FEditorStyle::GetBrush("Mobility.Static"))
]
+ SHorizontalBox::Slot()
.FillWidth(1.0f)
.VAlign(VAlign_Center)
.HAlign(HAlign_Center)
.Padding(2, 2)
[
SNew(STextBlock)
.Text( LOCTEXT( "LandscapeExportAsPointsCheckbox", "Points" ) )
.ToolTipText( PointsTooltip )
.Font( IDetailLayoutBuilder::GetDetailFont() )
]
]
];
}
// CheckBox : Export selected components only
{
TSharedPtr< SCheckBox > CheckBoxExportSelected;
VerticalBox->AddSlot().Padding( 2, 2, 5, 2 ).AutoHeight()
[
SAssignNew( CheckBoxExportSelected, SCheckBox )
.Content()
[
SNew( STextBlock )
.Text( LOCTEXT( "LandscapeSelectedCheckbox", "Export Selected Landscape Components Only" ) )
.ToolTipText( LOCTEXT( "LandscapeSelectedTooltip", "If enabled, only the selected Landscape Components will be exported." ) )
.Font( FEditorStyle::GetFontStyle( TEXT( "PropertyWindow.NormalFont") ) )
]
.IsChecked( TAttribute< ECheckBoxState >::Create(
TAttribute< ECheckBoxState >::FGetter::CreateUObject(
&InParam, &UHoudiniAssetInput::IsCheckedExportOnlySelected) ) )
.OnCheckStateChanged( FOnCheckStateChanged::CreateUObject(
&InParam, &UHoudiniAssetInput::CheckStateChangedExportOnlySelected ) )
];
}
// Checkboxes auto select components
{
TSharedPtr< SCheckBox > CheckBoxAutoSelectComponents;
VerticalBox->AddSlot().Padding(10, 2, 5, 2).AutoHeight()
[
SAssignNew( CheckBoxAutoSelectComponents, SCheckBox )
.Content()
[
SNew(STextBlock)
.Text( LOCTEXT( "AutoSelectComponentCheckbox", "Auto-select component in asset bounds" ) )
.ToolTipText( LOCTEXT( "AutoSelectComponentCheckboxTooltip", "If enabled, when no Landscape components are curremtly selected, the one within the asset's bounding box will be exported." ) )
.Font( FEditorStyle::GetFontStyle( TEXT( "PropertyWindow.NormalFont") ) )
]
.IsChecked( TAttribute< ECheckBoxState >::Create(
TAttribute< ECheckBoxState >::FGetter::CreateUObject(
&InParam, &UHoudiniAssetInput::IsCheckedAutoSelectLandscape ) ) )
.OnCheckStateChanged( FOnCheckStateChanged::CreateUObject(
&InParam, &UHoudiniAssetInput::CheckStateChangedAutoSelectLandscape) )
];
// Enable only when exporting selection
// or when exporting heighfield (for now)
if ( !InParam.bLandscapeExportSelectionOnly )
CheckBoxAutoSelectComponents->SetEnabled( false );
}
// The following checkbox are only added when not in heightfield mode
if ( !InParam.bLandscapeExportAsHeightfield )
{
// Checkbox : Export materials
{
TSharedPtr< SCheckBox > CheckBoxExportMaterials;
VerticalBox->AddSlot().Padding( 2, 2, 5, 2 ).AutoHeight()
[
SAssignNew( CheckBoxExportMaterials, SCheckBox )
.Content()
[
SNew( STextBlock )
.Text( LOCTEXT( "LandscapeMaterialsCheckbox", "Export Landscape Materials" ) )
.ToolTipText( LOCTEXT( "LandscapeMaterialsTooltip", "If enabled, the landscape materials will be exported with it." ) )
.Font( FEditorStyle::GetFontStyle( TEXT( "PropertyWindow.NormalFont" ) ) )
]
.IsChecked( TAttribute< ECheckBoxState >::Create(
TAttribute< ECheckBoxState >::FGetter::CreateUObject(
&InParam, &UHoudiniAssetInput::IsCheckedExportMaterials ) ) )
.OnCheckStateChanged( FOnCheckStateChanged::CreateUObject(
&InParam, &UHoudiniAssetInput::CheckStateChangedExportMaterials ) )
];
// Disable when exporting heightfields
if ( InParam.bLandscapeExportAsHeightfield )
CheckBoxExportMaterials->SetEnabled( false );
}
// Checkbox : Export Tile UVs
{
TSharedPtr< SCheckBox > CheckBoxExportTileUVs;
VerticalBox->AddSlot().Padding( 2, 2, 5, 2 ).AutoHeight()
[
SAssignNew( CheckBoxExportTileUVs, SCheckBox )
.Content()
[
SNew( STextBlock )
.Text( LOCTEXT( "LandscapeTileUVsCheckbox", "Export Landscape Tile UVs" ) )
.ToolTipText( LOCTEXT( "LandscapeTileUVsTooltip", "If enabled, UVs will be exported separately for each Landscape tile." ) )
.Font( FEditorStyle::GetFontStyle( TEXT( "PropertyWindow.NormalFont" ) ) )
]
.IsChecked(TAttribute< ECheckBoxState >::Create(
TAttribute< ECheckBoxState >::FGetter::CreateUObject(
&InParam, &UHoudiniAssetInput::IsCheckedExportTileUVs ) ) )
.OnCheckStateChanged( FOnCheckStateChanged::CreateUObject(
&InParam, &UHoudiniAssetInput::CheckStateChangedExportTileUVs ) )
];
// Disable when exporting heightfields
if ( InParam.bLandscapeExportAsHeightfield )
CheckBoxExportTileUVs->SetEnabled( false );
}
// Checkbox : Export normalized UVs
{
TSharedPtr< SCheckBox > CheckBoxExportNormalizedUVs;
VerticalBox->AddSlot().Padding( 2, 2, 5, 2 ).AutoHeight()
[
SAssignNew( CheckBoxExportNormalizedUVs, SCheckBox )
.Content()
[
SNew( STextBlock )
.Text( LOCTEXT( "LandscapeNormalizedUVsCheckbox", "Export Landscape Normalized UVs" ) )
.ToolTipText( LOCTEXT( "LandscapeNormalizedUVsTooltip", "If enabled, landscape UVs will be exported in [0, 1]." ) )
.Font( FEditorStyle::GetFontStyle( TEXT( "PropertyWindow.NormalFont" ) ) )
]
.IsChecked( TAttribute< ECheckBoxState >::Create(
TAttribute< ECheckBoxState >::FGetter::CreateUObject(
&InParam, &UHoudiniAssetInput::IsCheckedExportNormalizedUVs ) ) )
.OnCheckStateChanged(FOnCheckStateChanged::CreateUObject(
&InParam, &UHoudiniAssetInput::CheckStateChangedExportNormalizedUVs ) )
];
// Disable when exporting heightfields
if ( InParam.bLandscapeExportAsHeightfield )
CheckBoxExportNormalizedUVs->SetEnabled( false );
}
// Checkbox : Export lighting
{
TSharedPtr< SCheckBox > CheckBoxExportLighting;
VerticalBox->AddSlot().Padding( 2, 2, 5, 2 ).AutoHeight()
[
SAssignNew( CheckBoxExportLighting, SCheckBox )
.Content()
[
SNew( STextBlock )
.Text( LOCTEXT( "LandscapeLightingCheckbox", "Export Landscape Lighting" ) )
.ToolTipText( LOCTEXT( "LandscapeLightingTooltip", "If enabled, lightmap information will be exported with the landscape." ) )
.Font(FEditorStyle::GetFontStyle( TEXT( "PropertyWindow.NormalFont" ) ) )
]
.IsChecked( TAttribute< ECheckBoxState >::Create(
TAttribute< ECheckBoxState >::FGetter::CreateUObject(
&InParam, &UHoudiniAssetInput::IsCheckedExportLighting ) ) )
.OnCheckStateChanged( FOnCheckStateChanged::CreateUObject(
&InParam, &UHoudiniAssetInput::CheckStateChangedExportLighting ) )
];
// Disable when exporting heightfields
if ( InParam.bLandscapeExportAsHeightfield )
CheckBoxExportLighting->SetEnabled( false );
}
/*
// UNUSED
// Checkbox : Export landscape curves
{
TSharedPtr< SCheckBox > CheckBoxExportCurves;
VerticalBox->AddSlot().Padding( 2, 2, 5, 2 ).AutoHeight()
[
SAssignNew( CheckBoxExportCurves, SCheckBox )
.Content()
[
SNew( STextBlock )
.Text( LOCTEXT( "LandscapeCurvesCheckbox", "Export Landscape Curves" ) )
.ToolTipText( LOCTEXT( "LandscapeCurvesTooltip", "If enabled, Landscape curves will be exported." ) )
.Font( FEditorStyle::GetFontStyle( TEXT( "PropertyWindow.NormalFont" ) ) )
]
.IsChecked( TAttribute< ECheckBoxState >::Create(
TAttribute< ECheckBoxState >::FGetter::CreateUObject(
&InParam, &UHoudiniAssetInput::IsCheckedExportCurves ) ) )
.OnCheckStateChanged( FOnCheckStateChanged::CreateUObject(
&InParam, &UHoudiniAssetInput::CheckStateChangedExportCurves ) )
];
// Disable curves until we have them implemented.
if ( CheckBoxExportCurves.IsValid() )
CheckBoxExportCurves->SetEnabled( false );
}
*/
}
// Button : Recommit
VerticalBox->AddSlot().Padding( 2, 2, 5, 2 ).AutoHeight()
[
SNew( SHorizontalBox )
+SHorizontalBox::Slot()
.Padding( 1, 2, 4, 2 )
[
SNew( SButton )
.VAlign( VAlign_Center )
.HAlign( HAlign_Center )
.Text( LOCTEXT( "LandscapeInputRecommit", "Recommit Landscape" ) )
.ToolTipText( LOCTEXT( "LandscapeInputRecommitTooltip", "Recommits the Landscape to Houdini." ) )
.OnClicked( FOnClicked::CreateUObject( &InParam, &UHoudiniAssetInput::OnButtonClickRecommit ) )
]
];
}
else if ( InParam.ChoiceIndex == EHoudiniAssetInputType::WorldInput )
{
// Button : Start Selection / Use current selection + refresh
{
TSharedPtr< SHorizontalBox > HorizontalBox = NULL;
FPropertyEditorModule & PropertyModule =
FModuleManager::Get().GetModuleChecked< FPropertyEditorModule >( "PropertyEditor" );
// Get the details view
bool bDetailsLocked = false;
FName DetailsPanelName = "LevelEditorSelectionDetails";
const IDetailsView* DetailsView = DetailLayoutBuilder.GetDetailsView();
if ( DetailsView )
{
DetailsPanelName = DetailsView->GetIdentifier();
if ( DetailsView->IsLocked() )
bDetailsLocked = true;
}
auto ButtonLabel = LOCTEXT( "WorldInputStartSelection", "Start Selection (Locks Details Panel)" );
if ( bDetailsLocked )
ButtonLabel = LOCTEXT( "WorldInputUseCurrentSelection", "Use Current Selection (Unlocks Details Panel)" );
auto ButtonTooltip = LOCTEXT("WorldInputStartSelectionTooltip", "Locks the Details Panel, and allow you to select object in the world that you can commit to the input afterwards.");
if (bDetailsLocked)
ButtonTooltip = LOCTEXT("WorldInputUseCurrentSelectionTooltip", "Fill the asset's input with the current selection and unlocks the Details Panel.");
FOnClicked OnSelectActors = FOnClicked::CreateStatic( &FHoudiniParameterDetails::Helper_OnButtonClickSelectActors, MyParam, DetailsPanelName );
VerticalBox->AddSlot().Padding( 2, 2, 5, 2 ).AutoHeight()
[
SAssignNew( HorizontalBox, SHorizontalBox )
+ SHorizontalBox::Slot()
[
SNew( SButton )
.VAlign( VAlign_Center )
.HAlign( HAlign_Center )
.Text( ButtonLabel )
.ToolTipText( ButtonTooltip )
.OnClicked( OnSelectActors )
]
];
// Button : Use current selection as Bound selector
FOnClicked OnSelectBounds = FOnClicked::CreateStatic(&FHoudiniParameterDetails::Helper_OnButtonClickUseSelectionAsBoundSelector, MyParam, DetailsPanelName );
if ( bDetailsLocked )
{
ButtonLabel = LOCTEXT("WorldInputUseSelectionAsBoundSelector", "Use Selection as Bound Selector (Unlocks Details Panel)");
ButtonTooltip = LOCTEXT("WorldInputUseSelectionAsBoundSelectorTooltip", "Fill the asset's input with all the actors contains in the current's selection bound, and unlocks the Details Panel.");
VerticalBox->AddSlot().Padding( 2, 2, 5, 2 ).AutoHeight()
[
SAssignNew( HorizontalBox, SHorizontalBox )
+ SHorizontalBox::Slot()
[
SNew( SButton )
.VAlign( VAlign_Center )
.HAlign( HAlign_Center )
.Text( ButtonLabel )
.ToolTipText( ButtonTooltip )
.OnClicked( OnSelectBounds )
]
];
}
}
// ActorPicker : World Outliner
{
FMenuBuilder MenuBuilder = Helper_CreateCustomActorPickerWidget( InParam, LOCTEXT( "WorldInputSelectedActors", "Currently Selected Actors" ), false );
VerticalBox->AddSlot().Padding( 2, 2, 5, 2 ).AutoHeight()
[
MenuBuilder.MakeWidget()
];
}
{
// Spline Resolution
TSharedPtr< SNumericEntryBox< float > > NumericEntryBox;
int32 Idx = 0;
VerticalBox->AddSlot().Padding(2, 2, 5, 2).AutoHeight()
[
SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
[
SNew(STextBlock)
.Text(LOCTEXT("SplineRes", "Unreal Spline Resolution"))
.ToolTipText(LOCTEXT("SplineResTooltip", "Resolution used when marshalling the Unreal Splines to HoudiniEngine.\n(step in cm betweem control points)\nSet this to 0 to only export the control points."))
.Font(FEditorStyle::GetFontStyle(TEXT("PropertyWindow.NormalFont")))
]
+ SHorizontalBox::Slot()
.Padding(2.0f, 0.0f)
.VAlign(VAlign_Center)
[
SNew(SNumericEntryBox< float >)
.AllowSpin(true)
.Font(FEditorStyle::GetFontStyle(TEXT("PropertyWindow.NormalFont")))
.MinValue(-1.0f)
.MaxValue(1000.0f)
.MinSliderValue(0.0f)
.MaxSliderValue(1000.0f)
.Value(TAttribute< TOptional< float > >::Create(TAttribute< TOptional< float > >::FGetter::CreateUObject(
&InParam, &UHoudiniAssetInput::GetSplineResolutionValue) ) )
.OnValueChanged(SNumericEntryBox< float >::FOnValueChanged::CreateUObject(
&InParam, &UHoudiniAssetInput::SetSplineResolutionValue) )
.IsEnabled(TAttribute<bool>::Create(TAttribute<bool>::FGetter::CreateUObject(
&InParam, &UHoudiniAssetInput::IsSplineResolutionEnabled)))
.SliderExponent(1.0f)
]
+ SHorizontalBox::Slot()
.AutoWidth()
.Padding(2.0f, 0.0f)
.VAlign(VAlign_Center)
[
SNew(SButton)
.ToolTipText(LOCTEXT("SplineResToDefault", "Reset to default value."))
.ButtonStyle(FEditorStyle::Get(), "NoBorder")
.ContentPadding(0)
.Visibility(EVisibility::Visible)
.OnClicked(FOnClicked::CreateUObject(&InParam, &UHoudiniAssetInput::OnResetSplineResolutionClicked))
[
SNew(SImage)
.Image(FEditorStyle::GetBrush("PropertyWindow.DiffersFromDefault"))
]
]
];
}
}
if ( InParam.ChoiceIndex == EHoudiniAssetInputType::SkeletonInput )
{
const int32 NumInputs = InParam.SkeletonInputObjects.Num();
VerticalBox->AddSlot().Padding( 2, 2, 5, 2 ).AutoHeight()
[
SNew( SHorizontalBox )
+ SHorizontalBox::Slot()
.Padding( 1.0f )
.VAlign( VAlign_Center )
.AutoWidth()
[
SNew( STextBlock )
.Text( FText::Format( LOCTEXT( "NumArrayItemsFmt", "{0} elements" ), FText::AsNumber( NumInputs ) ) )
.Font( FEditorStyle::GetFontStyle( TEXT( "PropertyWindow.NormalFont" ) ) )
]
+ SHorizontalBox::Slot()
.Padding( 1.0f )
.VAlign( VAlign_Center )
.AutoWidth()
[
PropertyCustomizationHelpers::MakeAddButton( FSimpleDelegate::CreateUObject( &InParam, &UHoudiniAssetInput::OnAddToSkeletonInputObjects ), LOCTEXT( "AddSkeletonInput", "Adds a Skeleton Input" ), true )
]
+ SHorizontalBox::Slot()
.Padding( 1.0f )
.VAlign( VAlign_Center )
.AutoWidth()
[
PropertyCustomizationHelpers::MakeEmptyButton( FSimpleDelegate::CreateUObject( &InParam, &UHoudiniAssetInput::OnEmptySkeletonInputObjects ), LOCTEXT( "EmptySkeletonInputs", "Removes All Inputs" ), true )
]
];
for ( int32 Ix = 0; Ix < NumInputs; Ix++ )
{
UObject* InputObject = InParam.GetSkeletonInputObject( Ix );
Helper_CreateSkeletonWidget( InParam, Ix, InputObject, AssetThumbnailPool, VerticalBox );
}
}
Row.ValueWidget.Widget = VerticalBox;
Row.ValueWidget.MinDesiredWidth( HAPI_UNREAL_DESIRED_ROW_VALUE_WIDGET_WIDTH );
}
void
FHoudiniParameterDetails::CreateWidgetLabel( IDetailCategoryBuilder & LocalDetailCategoryBuilder, class UHoudiniAssetParameterLabel& InParam )
{
TSharedPtr< STextBlock > TextBlock;
FText ParameterLabelText = FText::FromString( InParam.GetParameterLabel() );
FText ParameterTooltip = GetParameterTooltip( &InParam );
LocalDetailCategoryBuilder.AddCustomRow( FText::GetEmpty() )
[
SAssignNew( TextBlock, STextBlock )
.Text( ParameterLabelText )
.ToolTipText( ParameterTooltip )
.Font( FEditorStyle::GetFontStyle( TEXT( "PropertyWindow.NormalFont" ) ) )
.WrapTextAt( HAPI_UNREAL_DESIRED_ROW_FULL_WIDGET_WIDTH )
.Justification( ETextJustify::Center )
];
if ( TextBlock.IsValid() )
TextBlock->SetEnabled( !InParam.bIsDisabled );
}
void
FHoudiniParameterDetails::CreateWidgetString( IDetailCategoryBuilder & LocalDetailCategoryBuilder, class UHoudiniAssetParameterString& InParam )
{
FDetailWidgetRow & Row = LocalDetailCategoryBuilder.AddCustomRow( FText::GetEmpty() );
// Create the standard parameter name widget.
CreateNameWidget( &InParam, Row, true );
TSharedRef< SVerticalBox > VerticalBox = SNew( SVerticalBox );
for ( int32 Idx = 0; Idx < InParam.GetTupleSize(); ++Idx )
{
TSharedPtr< SEditableTextBox > EditableTextBox;
VerticalBox->AddSlot().Padding( 2, 2, 5, 2 )
[
SAssignNew( EditableTextBox, SEditableTextBox )
.Font( FEditorStyle::GetFontStyle( TEXT( "PropertyWindow.NormalFont" ) ) )
.Text( FText::FromString( InParam.Values[Idx] ) )
.OnTextCommitted( FOnTextCommitted::CreateUObject(
&InParam, &UHoudiniAssetParameterString::SetValueCommitted, Idx ) )
];
if ( EditableTextBox.IsValid() )
EditableTextBox->SetEnabled( !InParam.bIsDisabled );
}
Row.ValueWidget.Widget = VerticalBox;
Row.ValueWidget.MinDesiredWidth( HAPI_UNREAL_DESIRED_ROW_VALUE_WIDGET_WIDTH );
}
void
FHoudiniParameterDetails::CreateWidgetSeparator( IDetailCategoryBuilder & LocalDetailCategoryBuilder, class UHoudiniAssetParameterSeparator& InParam )
{
TSharedPtr< SSeparator > Separator;
LocalDetailCategoryBuilder.AddCustomRow( FText::GetEmpty() )
[
SNew( SVerticalBox )
+SVerticalBox::Slot()
.Padding( 0, 0, 5, 0 )
[
SAssignNew( Separator, SSeparator )
.Thickness( 2.0f )
]
];
if ( Separator.IsValid() )
Separator->SetEnabled( !InParam.bIsDisabled );
}
#undef LOCTEXT_NAMESPACE