Files
Andron666 9c38e93fa4 part7
2022-12-05 20:31:35 +05:00

2636 lines
83 KiB
C++

/*
* Copyright (c) <2021> Side Effects Software Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. The name of Side Effects Software may not be used to endorse or
* promote products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY SIDE EFFECTS SOFTWARE "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
* NO EVENT SHALL SIDE EFFECTS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "HoudiniPDGDetails.h"
#include "HoudiniEngineEditorPrivatePCH.h"
#include "HoudiniPDGAssetLink.h"
#include "HoudiniPDGManager.h"
#include "HoudiniEngineUtils.h"
#include "HoudiniEngineRuntimePrivatePCH.h"
#include "HoudiniAssetActor.h"
#include "HoudiniEngine.h"
#include "HoudiniEngineBakeUtils.h"
#include "HoudiniEngineCommands.h"
#include "HoudiniEngineDetails.h"
#include "HoudiniEngineEditor.h"
#include "HoudiniEngineEditorUtils.h"
#include "DetailCategoryBuilder.h"
#include "DetailLayoutBuilder.h"
#include "IDetailGroup.h"
#include "IDetailCustomization.h"
#include "PropertyCustomizationHelpers.h"
#include "DetailWidgetRow.h"
#include "ScopedTransaction.h"
#include "Widgets/Input/SButton.h"
#include "Widgets/Input/SCheckBox.h"
#include "Widgets/Input/SComboBox.h"
#include "Widgets/Input/SEditableTextBox.h"
#include "Widgets/Images/SImage.h"
#include "Widgets/SBoxPanel.h"
#include "Widgets/Layout/SSpacer.h"
#include "Framework/SlateDelegates.h"
#include "Templates/SharedPointer.h"
#include "Internationalization/Internationalization.h"
#define LOCTEXT_NAMESPACE HOUDINI_LOCTEXT_NAMESPACE
#define HOUDINI_ENGINE_UI_SECTION_PDG_BAKE 2
void
FHoudiniPDGDetails::CreateWidget(
IDetailCategoryBuilder& HouPDGCategory,
UHoudiniPDGAssetLink* InPDGAssetLink)
{
if (!InPDGAssetLink || InPDGAssetLink->IsPendingKill())
return;
// PDG ASSET
FHoudiniPDGDetails::AddPDGAssetWidget(HouPDGCategory, InPDGAssetLink);
// TOP NETWORKS
FHoudiniPDGDetails::AddTOPNetworkWidget(HouPDGCategory, InPDGAssetLink);
// PDG EVENT MESSAGES
}
void
FHoudiniPDGDetails::AddPDGAssetWidget(
IDetailCategoryBuilder& InPDGCategory, UHoudiniPDGAssetLink* InPDGAssetLink)
{
// PDG STATUS ROW
AddPDGAssetStatus(InPDGCategory, InPDGAssetLink);
// Commandlet Status row
AddPDGCommandletStatus(InPDGCategory, FHoudiniEngine::Get().GetPDGCommandletStatus());
// REFRESH / RESET Buttons
{
TSharedRef<SHorizontalBox> RefreshHBox = SNew(SHorizontalBox);
TSharedPtr<SHorizontalBox> ResetHBox = SNew(SHorizontalBox);
FDetailWidgetRow& PDGRefreshResetRow = InPDGCategory.AddCustomRow(FText::GetEmpty())
.WholeRowContent()
[
SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
.AutoWidth()
.VAlign(VAlign_Center)
.HAlign(HAlign_Center)
[
SNew(SBox)
.WidthOverride(200.0f)
[
SNew(SButton)
//.Text(LOCTEXT("Refresh", "Refresh"))
.ToolTipText(LOCTEXT("RefreshTooltip", "Refreshes infos displayed by the the PDG Asset Link"))
.ContentPadding(FMargin(5.0f, 5.0f))
.VAlign(VAlign_Center)
.HAlign(HAlign_Center)
.OnClicked_Lambda([InPDGAssetLink]()
{
FHoudiniPDGDetails::RefreshPDGAssetLink(InPDGAssetLink);
return FReply::Handled();
})
.Content()
[
SAssignNew(RefreshHBox, SHorizontalBox)
]
]
]
+ SHorizontalBox::Slot()
.AutoWidth()
[
SNew(SBox)
.WidthOverride(200.0f)
[
SNew(SButton)
//.Text(LOCTEXT("Reset", "Reset"))
.ToolTipText(LOCTEXT("ResetTooltip", "Resets the PDG Asset Link"))
.ContentPadding(FMargin(5.0f, 5.0f))
.VAlign(VAlign_Center)
.HAlign(HAlign_Center)
.OnClicked_Lambda([InPDGAssetLink]()
{
// TODO: RESET USELESS?
FHoudiniPDGDetails::RefreshUI(InPDGAssetLink);
return FReply::Handled();
})
.Content()
[
SAssignNew(ResetHBox, SHorizontalBox)
]
]
]
];
TSharedPtr<FSlateDynamicImageBrush> RefreshIconBrush = FHoudiniEngineEditor::Get().GetHoudiniEngineUIPDGRefreshIconBrush();
if (RefreshIconBrush.IsValid())
{
TSharedPtr<SImage> RefreshImage;
RefreshHBox->AddSlot()
.MaxWidth(16.0f)
[
SNew(SBox)
.WidthOverride(16.0f)
.HeightOverride(16.0f)
[
SAssignNew(RefreshImage, SImage)
]
];
RefreshImage->SetImage(
TAttribute<const FSlateBrush*>::Create(
TAttribute<const FSlateBrush*>::FGetter::CreateLambda([RefreshIconBrush]() { return RefreshIconBrush.Get(); })));
}
RefreshHBox->AddSlot()
.Padding(5.0, 0.0, 0.0, 0.0)
.VAlign(VAlign_Center)
.AutoWidth()
[
SNew(STextBlock)
.Text(LOCTEXT("Refresh", "Refresh"))
];
TSharedPtr<FSlateDynamicImageBrush> ResetIconBrush = FHoudiniEngineEditor::Get().GetHoudiniEngineUIPDGResetIconBrush();
if (ResetIconBrush.IsValid())
{
TSharedPtr<SImage> ResetImage;
ResetHBox->AddSlot()
.MaxWidth(16.0f)
[
SNew(SBox)
.WidthOverride(16.0f)
.HeightOverride(16.0f)
[
SAssignNew(ResetImage, SImage)
]
];
ResetImage->SetImage(
TAttribute<const FSlateBrush*>::Create(
TAttribute<const FSlateBrush*>::FGetter::CreateLambda([ResetIconBrush]() { return ResetIconBrush.Get(); })));
}
ResetHBox->AddSlot()
.Padding(5.0, 0.0, 0.0, 0.0)
.VAlign(VAlign_Center)
.AutoWidth()
[
SNew(STextBlock)
.Text(LOCTEXT("Reset", "Reset"))
];
}
// TOP NODE FILTER
{
FText Tooltip = FText::FromString(TEXT("When enabled, the TOP Node Filter will only display the TOP Nodes found in the current network that start with the filter prefix. Disabling the Filter will display all of the TOP Network's TOP Nodes."));
// Lambda for changing the filter value
auto ChangeTOPNodeFilter = [InPDGAssetLink](const FString& NewValue)
{
if (InPDGAssetLink->TOPNodeFilter.Equals(NewValue))
return;
// Record a transaction for undo/redo
FScopedTransaction Transaction(
TEXT(HOUDINI_MODULE_RUNTIME),
LOCTEXT("HoudiniPDGAssetLinkParameterChange", "Houdini PDG Asset Link Parameter: Changing a value"),
InPDGAssetLink);
InPDGAssetLink->Modify();
InPDGAssetLink->TOPNodeFilter = NewValue;
// Notify that we have changed the property
FHoudiniEngineEditorUtils::NotifyPostEditChangeProperty(
GET_MEMBER_NAME_STRING_CHECKED(UHoudiniPDGAssetLink, TOPNodeFilter), InPDGAssetLink);
};
FDetailWidgetRow& PDGFilterRow = InPDGCategory.AddCustomRow(FText::GetEmpty());
// Disable if PDG is not linked
DisableIfPDGNotLinked(PDGFilterRow, InPDGAssetLink);
PDGFilterRow.NameWidget.Widget =
SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
.AutoWidth()
.Padding(2.0f, 0.0f)
[
// Checkbox enable filter
SNew(SCheckBox)
.IsChecked_Lambda([InPDGAssetLink]()
{
return InPDGAssetLink->bUseTOPNodeFilter ? ECheckBoxState::Checked : ECheckBoxState::Unchecked;;
})
.OnCheckStateChanged_Lambda([InPDGAssetLink](ECheckBoxState NewState)
{
bool bNewState = (NewState == ECheckBoxState::Checked) ? true : false;
if (InPDGAssetLink->bUseTOPNodeFilter == bNewState)
return;
// Record a transaction for undo/redo
FScopedTransaction Transaction(
TEXT(HOUDINI_MODULE_RUNTIME),
LOCTEXT("HoudiniPDGAssetLinkParameterChange", "Houdini PDG Asset Link Parameter: Changing a value"),
InPDGAssetLink);
InPDGAssetLink->Modify();
InPDGAssetLink->bUseTOPNodeFilter = bNewState;
// Notify that we have changed the property
FHoudiniEngineEditorUtils::NotifyPostEditChangeProperty(
GET_MEMBER_NAME_STRING_CHECKED(UHoudiniPDGAssetLink, bUseTOPNodeFilter), InPDGAssetLink);
})
.ToolTipText(Tooltip)
]
+ SHorizontalBox::Slot()
.AutoWidth()
.Padding(2.0f, 0.0f)
[
SNew(STextBlock)
.Text(FText::FromString(TEXT("TOP Node Filter")))
.ToolTipText(Tooltip)
];
PDGFilterRow.ValueWidget.Widget =
SNew(SHorizontalBox)
+ SHorizontalBox::Slot().FillWidth(1.0f)
[
SNew(SEditableTextBox)
.Font(FEditorStyle::GetFontStyle(TEXT("PropertyWindow.NormalFont")))
.ToolTipText(Tooltip)
.Text_Lambda([InPDGAssetLink]()
{
if (!IsValid(InPDGAssetLink))
return FText();
return FText::FromString(InPDGAssetLink->TOPNodeFilter);
})
.OnTextCommitted_Lambda([ChangeTOPNodeFilter](const FText& Val, ETextCommit::Type TextCommitType)
{
ChangeTOPNodeFilter(Val.ToString());
})
]
+ SHorizontalBox::Slot()
.AutoWidth()
.Padding(2.0f, 0.0f)
.VAlign(VAlign_Center)
[
SNew(SButton)
.ToolTipText(LOCTEXT("RevertToDefault", "Revert to default"))
.ButtonStyle(FEditorStyle::Get(), "NoBorder")
.ContentPadding(0)
.Visibility(EVisibility::Visible)
.OnClicked_Lambda([=]()
{
FString DefaultFilter = TEXT(HAPI_UNREAL_PDG_DEFAULT_TOP_FILTER);
ChangeTOPNodeFilter(DefaultFilter);
return FReply::Handled();
})
[
SNew(SImage)
.Image(FEditorStyle::GetBrush("PropertyWindow.DiffersFromDefault"))
]
];
}
// TOP OUTPUT FILTER
{
// Lambda for changing the filter value
FText Tooltip = FText::FromString(TEXT("When enabled, the Work Item Output Files created for the TOP Nodes found in the current network that start with the filter prefix will be automatically loaded int the world after being cooked."));
auto ChangeTOPOutputFilter = [InPDGAssetLink](const FString& NewValue)
{
if (InPDGAssetLink->TOPOutputFilter.Equals(NewValue))
return;
// Record a transaction for undo/redo
FScopedTransaction Transaction(
TEXT(HOUDINI_MODULE_RUNTIME),
LOCTEXT("HoudiniPDGAssetLinkParameterChange", "Houdini PDG Asset Link Parameter: Changing a value"),
InPDGAssetLink);
InPDGAssetLink->Modify();
InPDGAssetLink->TOPOutputFilter = NewValue;
// Notify that we have changed the property
FHoudiniEngineEditorUtils::NotifyPostEditChangeProperty(
GET_MEMBER_NAME_STRING_CHECKED(UHoudiniPDGAssetLink, TOPOutputFilter), InPDGAssetLink);
};
FDetailWidgetRow& PDGOutputFilterRow = InPDGCategory.AddCustomRow(FText::GetEmpty());
// Disable if PDG is not linked
DisableIfPDGNotLinked(PDGOutputFilterRow, InPDGAssetLink);
PDGOutputFilterRow.NameWidget.Widget =
SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
.AutoWidth()
.Padding(2.0f, 0.0f)
[
// Checkbox enable filter
SNew(SCheckBox)
.IsChecked_Lambda([InPDGAssetLink]()
{
return InPDGAssetLink->bUseTOPOutputFilter ? ECheckBoxState::Checked : ECheckBoxState::Unchecked;
})
.OnCheckStateChanged_Lambda([InPDGAssetLink](ECheckBoxState NewState)
{
bool bNewState = (NewState == ECheckBoxState::Checked) ? true : false;
if (InPDGAssetLink->bUseTOPOutputFilter == bNewState)
return;
// Record a transaction for undo/redo
FScopedTransaction Transaction(
TEXT(HOUDINI_MODULE_RUNTIME),
LOCTEXT("HoudiniPDGAssetLinkParameterChange", "Houdini PDG Asset Link Parameter: Changing a value"),
InPDGAssetLink);
InPDGAssetLink->Modify();
InPDGAssetLink->bUseTOPOutputFilter = bNewState;
// Notify that we have changed the property
FHoudiniEngineEditorUtils::NotifyPostEditChangeProperty(
GET_MEMBER_NAME_STRING_CHECKED(UHoudiniPDGAssetLink, bUseTOPOutputFilter), InPDGAssetLink);
})
.ToolTipText(Tooltip)
]
+ SHorizontalBox::Slot()
.AutoWidth()
.Padding(2.0f, 0.0f)
[
SNew(STextBlock)
.Text(FText::FromString(TEXT("TOP Output Filter")))
.ToolTipText(Tooltip)
];
PDGOutputFilterRow.ValueWidget.Widget =
SNew(SHorizontalBox)
+ SHorizontalBox::Slot().FillWidth(1.0f)
[
SNew(SEditableTextBox)
.Font(FEditorStyle::GetFontStyle(TEXT("PropertyWindow.NormalFont")))
.Text_Lambda([InPDGAssetLink]()
{
if (!IsValid(InPDGAssetLink))
return FText();
return FText::FromString(InPDGAssetLink->TOPOutputFilter);
})
.OnTextCommitted_Lambda([ChangeTOPOutputFilter](const FText& Val, ETextCommit::Type TextCommitType)
{
ChangeTOPOutputFilter(Val.ToString());
})
.ToolTipText(Tooltip)
]
+ SHorizontalBox::Slot()
.AutoWidth()
.Padding(2.0f, 0.0f)
.VAlign(VAlign_Center)
[
SNew(SButton)
.ToolTipText(LOCTEXT("RevertToDefault", "Revert to default"))
.ButtonStyle(FEditorStyle::Get(), "NoBorder")
.ContentPadding(0)
.Visibility(EVisibility::Visible)
.OnClicked_Lambda([ChangeTOPOutputFilter]()
{
FString DefaultFilter = TEXT(HAPI_UNREAL_PDG_DEFAULT_TOP_OUTPUT_FILTER);
ChangeTOPOutputFilter(DefaultFilter);
return FReply::Handled();
})
[
SNew(SImage)
.Image(FEditorStyle::GetBrush("PropertyWindow.DiffersFromDefault"))
]
];
}
// Checkbox: Autocook
{
FText Tooltip = FText::FromString(TEXT("When enabled, the selected TOP Network's output will automatically cook after succesfully cooking the PDG Asset Link HDA."));
FDetailWidgetRow& PDGAutocookRow = InPDGCategory.AddCustomRow(FText::GetEmpty());
// Disable if PDG is not linked
DisableIfPDGNotLinked(PDGAutocookRow, InPDGAssetLink);
PDGAutocookRow.NameWidget.Widget =
SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
.AutoWidth()
.Padding(2.0f, 0.0f)
[
SNew(STextBlock)
.Text(FText::FromString(TEXT("Auto-cook")))
.ToolTipText(Tooltip)
];
TSharedPtr<SCheckBox> AutoCookCheckBox;
PDGAutocookRow.ValueWidget.Widget =
SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
.AutoWidth()
.Padding(2.0f, 0.0f)
[
// Checkbox
SAssignNew(AutoCookCheckBox, SCheckBox)
.IsChecked_Lambda([InPDGAssetLink]()
{
return InPDGAssetLink->bAutoCook ? ECheckBoxState::Checked : ECheckBoxState::Unchecked;
})
.OnCheckStateChanged_Lambda([InPDGAssetLink](ECheckBoxState NewState)
{
bool bNewState = (NewState == ECheckBoxState::Checked) ? true : false;
if (!InPDGAssetLink || InPDGAssetLink->bAutoCook == bNewState)
return;
// Record a transaction for undo/redo
FScopedTransaction Transaction(
TEXT(HOUDINI_MODULE_RUNTIME),
LOCTEXT("HoudiniPDGAssetLinkParameterChange", "Houdini PDG Asset Link Parameter: Changing a value"),
InPDGAssetLink);
InPDGAssetLink->Modify();
InPDGAssetLink->bAutoCook = bNewState;
FHoudiniEngineEditorUtils::NotifyPostEditChangeProperty(
GET_MEMBER_NAME_STRING_CHECKED(UHoudiniPDGAssetLink, bAutoCook), InPDGAssetLink);
})
.ToolTipText(Tooltip)
];
}
// Output parent actor selector
{
IDetailPropertyRow* PDGOutputParentActorRow = InPDGCategory.AddExternalObjectProperty({ InPDGAssetLink }, "OutputParentActor");
if (PDGOutputParentActorRow)
{
TAttribute<bool> PDGOutputParentActorRowEnabled;
BindDisableIfPDGNotLinked(PDGOutputParentActorRowEnabled, InPDGAssetLink);
PDGOutputParentActorRow->IsEnabled(PDGOutputParentActorRowEnabled);
TSharedPtr<SWidget> NameWidget;
TSharedPtr<SWidget> ValueWidget;
PDGOutputParentActorRow->GetDefaultWidgets(NameWidget, ValueWidget);
PDGOutputParentActorRow->DisplayName(FText::FromString(TEXT("Output Parent Actor")));
PDGOutputParentActorRow->ToolTip(FText::FromString(
TEXT("The PDG Output Actors will be created under this parent actor. If not set, then the PDG Output Actors will be created under a new folder.")));
}
}
// Add bake widgets for PDG output
CreatePDGBakeWidgets(InPDGCategory, InPDGAssetLink);
// TODO: move this to a better place: the baking code is in HoudiniEngineEditor, the PDG manager (that knows about
// when work object results are loaded is in HoudiniEngine and the PDGAssetLink is in HoudiniEngineRuntime). So
// we bind an auto-bake helper function here. Maybe the baking code can move to HoudiniEngine?
if (InPDGAssetLink->AutoBakeDelegateHandle.IsValid())
InPDGAssetLink->OnWorkResultObjectLoaded.Remove(InPDGAssetLink->AutoBakeDelegateHandle);
InPDGAssetLink->AutoBakeDelegateHandle = InPDGAssetLink->OnWorkResultObjectLoaded.AddStatic(FHoudiniEngineBakeUtils::CheckPDGAutoBakeAfterResultObjectLoaded);
// WORK ITEM STATUS
{
FDetailWidgetRow& PDGStatusRow = InPDGCategory.AddCustomRow(FText::GetEmpty());
// Disable if PDG is not linked
DisableIfPDGNotLinked(PDGStatusRow, InPDGAssetLink);
FHoudiniPDGDetails::AddWorkItemStatusWidget(
PDGStatusRow, TEXT("Asset Work Item Status"), InPDGAssetLink, false);
}
}
bool
FHoudiniPDGDetails::GetPDGStatusAndColor(
UHoudiniPDGAssetLink* InPDGAssetLink, FString& OutPDGStatusString, FLinearColor& OutPDGStatusColor)
{
OutPDGStatusString = FString();
OutPDGStatusColor = FLinearColor::White;
if (!IsValid(InPDGAssetLink))
return false;
switch (InPDGAssetLink->LinkState)
{
case EPDGLinkState::Linked:
OutPDGStatusString = TEXT("PDG is READY");
OutPDGStatusColor = FLinearColor::Green;
break;
case EPDGLinkState::Linking:
OutPDGStatusString = TEXT("PDG is Linking");
OutPDGStatusColor = FLinearColor::Yellow;
break;
case EPDGLinkState::Error_Not_Linked:
OutPDGStatusString = TEXT("PDG is ERRORED");
OutPDGStatusColor = FLinearColor::Red;
break;
case EPDGLinkState::Inactive:
OutPDGStatusString = TEXT("PDG is INACTIVE");
OutPDGStatusColor = FLinearColor::White;
break;
default:
return false;
}
return true;
}
void
FHoudiniPDGDetails::AddPDGAssetStatus(
IDetailCategoryBuilder& InPDGCategory, UHoudiniPDGAssetLink *InPDGAssetLink)
{
FDetailWidgetRow& PDGStatusRow = InPDGCategory.AddCustomRow(FText::GetEmpty())
.WholeRowContent()
[
SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
.FillWidth(1.0f)
.Padding(2.0f, 0.0f)
.VAlign(VAlign_Center)
.HAlign(HAlign_Center)
[
SNew(STextBlock)
.Text_Lambda([InPDGAssetLink]()
{
FString PDGStatusString;
FLinearColor PDGStatusColor;
GetPDGStatusAndColor(InPDGAssetLink, PDGStatusString, PDGStatusColor);
return FText::FromString(PDGStatusString);
})
.ColorAndOpacity_Lambda([InPDGAssetLink]()
{
FString PDGStatusString;
FLinearColor PDGStatusColor;
GetPDGStatusAndColor(InPDGAssetLink, PDGStatusString, PDGStatusColor);
return FSlateColor(PDGStatusColor);
})
]
];
}
void
FHoudiniPDGDetails::GetPDGCommandletStatus(FString& OutStatusString, FLinearColor& OutStatusColor)
{
OutStatusString = FString();
OutStatusColor = FLinearColor::White;
switch (FHoudiniEngine::Get().GetPDGCommandletStatus())
{
case EHoudiniBGEOCommandletStatus::Connected:
OutStatusString = TEXT("Async importer is CONNECTED");
OutStatusColor = FLinearColor::Green;
break;
case EHoudiniBGEOCommandletStatus::Running:
OutStatusString = TEXT("Async importer is Running");
OutStatusColor = FLinearColor::Yellow;
break;
case EHoudiniBGEOCommandletStatus::Crashed:
OutStatusString = TEXT("Async importer has CRASHED");
OutStatusColor = FLinearColor::Red;
break;
case EHoudiniBGEOCommandletStatus::NotStarted:
OutStatusString = TEXT("Async importer is NOT STARTED");
OutStatusColor = FLinearColor::White;
break;
}
}
void
FHoudiniPDGDetails::AddPDGCommandletStatus(
IDetailCategoryBuilder& InPDGCategory, const EHoudiniBGEOCommandletStatus& InCommandletStatus)
{
FDetailWidgetRow& PDGStatusRow = InPDGCategory.AddCustomRow(FText::GetEmpty())
.WholeRowContent()
[
SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
.FillWidth(1.0f)
.Padding(2.0f, 0.0f)
.VAlign(VAlign_Center)
.HAlign(HAlign_Center)
[
SNew(STextBlock)
.Visibility_Lambda([]()
{
const UHoudiniRuntimeSettings* Settings = GetDefault<UHoudiniRuntimeSettings>();
if (IsValid(Settings))
{
return FHoudiniEngineCommands::IsPDGCommandletEnabled() ? EVisibility::Visible : EVisibility::Collapsed;
}
return EVisibility::Visible;
})
.Text_Lambda([]()
{
FString StatusString;
FLinearColor StatusColor;
GetPDGCommandletStatus(StatusString, StatusColor);
return FText::FromString(StatusString);
})
.ColorAndOpacity_Lambda([]()
{
FString StatusString;
FLinearColor StatusColor;
GetPDGCommandletStatus(StatusString, StatusColor);
return FSlateColor(StatusColor);
})
]
];
}
bool
FHoudiniPDGDetails::GetWorkItemTallyValueAndColor(
UHoudiniPDGAssetLink* InAssetLink,
bool bInForSelectedNode,
const FString& InTallyItemString,
int32& OutValue,
FLinearColor& OutColor)
{
OutValue = 0;
OutColor = FLinearColor::White;
if (!IsValid(InAssetLink))
return false;
bool bFound = false;
const FWorkItemTallyBase* TallyPtr = nullptr;
if (bInForSelectedNode)
{
UTOPNode* const TOPNode = InAssetLink->GetSelectedTOPNode();
if (TOPNode && !TOPNode->bHidden)
TallyPtr = &(TOPNode->GetWorkItemTally());
}
else
TallyPtr = &(InAssetLink->WorkItemTally);
if (TallyPtr)
{
if (InTallyItemString == TEXT("WAITING"))
{
// For now we add waiting and scheduled together, since there is no separate column for scheduled on the UI
OutValue = TallyPtr->NumWaitingWorkItems() + TallyPtr->NumScheduledWorkItems();
OutColor = OutValue > 0 ? FLinearColor(0.0f, 1.0f, 1.0f) : FLinearColor::White;
bFound = true;
}
else if (InTallyItemString == TEXT("COOKING"))
{
OutValue = TallyPtr->NumCookingWorkItems();
OutColor = OutValue > 0 ? FLinearColor::Yellow : FLinearColor::White;
bFound = true;
}
else if (InTallyItemString == TEXT("COOKED"))
{
OutValue = TallyPtr->NumCookedWorkItems();
OutColor = OutValue > 0 ? FLinearColor::Green : FLinearColor::White;
bFound = true;
}
else if (InTallyItemString == TEXT("FAILED"))
{
OutValue = TallyPtr->NumErroredWorkItems();
OutColor = OutValue > 0 ? FLinearColor::Red : FLinearColor::White;
bFound = true;
}
}
return bFound;
}
void
FHoudiniPDGDetails::AddWorkItemStatusWidget(
FDetailWidgetRow& InRow, const FString& InTitleString, UHoudiniPDGAssetLink* InAssetLink, bool bInForSelectedNode)
{
auto AddGridBox = [InAssetLink, bInForSelectedNode](const FString& Title) -> SHorizontalBox::FSlot&
{
return SHorizontalBox::Slot()
.MaxWidth(500.0f)
.Padding(0.0f, 0.0f, 2.0f, 0.0f)
.VAlign(VAlign_Center)
.HAlign(HAlign_Center)
[
SNew(SVerticalBox)
+ SVerticalBox::Slot()
.VAlign(VAlign_Center)
.HAlign(HAlign_Center)
.AutoHeight()
.Padding(FMargin(1.0f, 2.0f))
[
SNew(SBorder)
.IsEnabled_Lambda([InAssetLink]() { return IsPDGLinked(InAssetLink); })
.BorderImage(FEditorStyle::GetBrush("ToolPanel.GroupBorder"))
.BorderBackgroundColor(FSlateColor(FLinearColor(0.6, 0.6, 0.6)))
.Padding(FMargin(1.0f, 5.0f))
[
SNew(SBox)
.WidthOverride(95.0f)
.VAlign(VAlign_Center)
.HAlign(HAlign_Center)
[
SNew(STextBlock)
.Text(FText::FromString(Title))
.ColorAndOpacity_Lambda([InAssetLink, bInForSelectedNode, Title]()
{
int32 Value;
FLinearColor Color;
GetWorkItemTallyValueAndColor(InAssetLink, bInForSelectedNode, Title, Value, Color);
return FSlateColor(Color);
})
]
]
]
+ SVerticalBox::Slot()
.VAlign(VAlign_Center)
.HAlign(HAlign_Center)
.AutoHeight()
.Padding(FMargin(1.0f, 2.0f))
[
SNew(SBorder)
.IsEnabled_Lambda([InAssetLink]() { return IsPDGLinked(InAssetLink); })
.BorderImage(FEditorStyle::GetBrush("ToolPanel.GroupBorder"))
.BorderBackgroundColor(FSlateColor(FLinearColor(0.8, 0.8, 0.8)))
.Padding(FMargin(1.0f, 5.0f))
[
SNew(SBox)
.WidthOverride(95.0f)
.VAlign(VAlign_Center)
.HAlign(HAlign_Center)
[
SNew(STextBlock)
.Text_Lambda([InAssetLink, bInForSelectedNode, Title]()
{
int32 Value;
FLinearColor Color;
GetWorkItemTallyValueAndColor(InAssetLink, bInForSelectedNode, Title, Value, Color);
return FText::AsNumber(Value);
})
.ColorAndOpacity_Lambda([InAssetLink, bInForSelectedNode, Title]()
{
int32 Value;
FLinearColor Color;
GetWorkItemTallyValueAndColor(InAssetLink, bInForSelectedNode, Title, Value, Color);
return FSlateColor(Color);
})
]
]
]
];
};
InRow.WholeRowContent()
[
SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
.Padding(0.0f, 0.0f)
.AutoWidth()
[
SNew(SVerticalBox)
+SVerticalBox::Slot()
[
SNew(SSpacer)
]
+ SVerticalBox::Slot()
.AutoHeight()
.VAlign(VAlign_Center)
.HAlign(HAlign_Center)
.Padding(FMargin(0.0f, 2.0f))
[
SNew(STextBlock)
.IsEnabled_Lambda([InAssetLink]() { return IsPDGLinked(InAssetLink); })
.Text(FText::FromString(InTitleString))
]
+ SVerticalBox::Slot()
.AutoHeight()
.VAlign(VAlign_Center)
.HAlign(HAlign_Center)
.Padding(FMargin(0.0f, 2.0f))
[
SNew(SHorizontalBox)
+ AddGridBox(TEXT("WAITING"))
+ AddGridBox(TEXT("COOKING"))
+ AddGridBox(TEXT("COOKED"))
+ AddGridBox(TEXT("FAILED"))
]
+ SVerticalBox::Slot()
[
SNew(SSpacer)
]
]
];
}
void
FHoudiniPDGDetails::AddTOPNetworkWidget(
IDetailCategoryBuilder& InPDGCategory, UHoudiniPDGAssetLink* InPDGAssetLink )
{
if (!InPDGAssetLink->GetSelectedTOPNetwork())
return;
if (InPDGAssetLink->AllTOPNetworks.Num() <= 0)
return;
TOPNetworksPtr.Reset();
FString GroupLabel = TEXT("TOP Networks");
IDetailGroup& TOPNetWorkGrp = InPDGCategory.AddGroup(FName(*GroupLabel), FText::FromString(GroupLabel), false, true);
// Combobox: TOP Network
{
FDetailWidgetRow& PDGTOPNetRow = TOPNetWorkGrp.AddWidgetRow();
// DisableIfPDGNotLinked(PDGTOPNetRow, InPDGAssetLink);
PDGTOPNetRow.NameWidget.Widget =
SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
[
SNew(STextBlock)
.Text(FText::FromString(TEXT("TOP Network")))
];
// Fill the TOP Networks SharedString array
TOPNetworksPtr.SetNum(InPDGAssetLink->AllTOPNetworks.Num());
for(int32 Idx = 0; Idx < InPDGAssetLink->AllTOPNetworks.Num(); Idx++)
{
const UTOPNetwork* Network = InPDGAssetLink->AllTOPNetworks[Idx];
if (!IsValid(Network))
{
TOPNetworksPtr[Idx] = MakeShareable(new FTextAndTooltip(
Idx,
TEXT("Invalid"),
TEXT("Invalid")
));
}
else
{
TOPNetworksPtr[Idx] = MakeShareable(new FTextAndTooltip(
Idx,
FHoudiniEngineEditorUtils::GetNodeNamePaddedByPathDepth(Network->NodeName, Network->NodePath),
Network->NodePath
));
}
}
if(TOPNetworksPtr.Num() <= 0)
TOPNetworksPtr.Add(MakeShareable(new FTextAndTooltip(INDEX_NONE, "----")));
// Lambda for selecting another TOPNet
auto OnTOPNetChanged = [InPDGAssetLink](TSharedPtr<FTextAndTooltip> InNewChoice)
{
if (!InNewChoice.IsValid())
return;
const int32 NewChoice = InNewChoice->Value;
int32 NewSelectedIndex = -1;
if (InPDGAssetLink->AllTOPNetworks.IsValidIndex(NewChoice))
NewSelectedIndex = NewChoice;
if (InPDGAssetLink->SelectedTOPNetworkIndex == NewSelectedIndex)
return;
if (NewSelectedIndex < 0)
return;
// Record a transaction for undo/redo
FScopedTransaction Transaction(
TEXT(HOUDINI_MODULE_RUNTIME),
LOCTEXT("HoudiniPDGAssetLinkParameterChange", "Houdini PDG Asset Link Parameter: Changing a value"),
InPDGAssetLink);
InPDGAssetLink->Modify();
InPDGAssetLink->SelectedTOPNetworkIndex = NewSelectedIndex;
FHoudiniEngineEditorUtils::NotifyPostEditChangeProperty(
GET_MEMBER_NAME_STRING_CHECKED(UHoudiniPDGAssetLink, SelectedTOPNetworkIndex), InPDGAssetLink);
};
TSharedPtr<SHorizontalBox, ESPMode::NotThreadSafe> HorizontalBoxTOPNet;
TSharedPtr<SComboBox<TSharedPtr<FTextAndTooltip>>> ComboBoxTOPNet;
int32 SelectedIndex = TOPNetworksPtr.IndexOfByPredicate([InPDGAssetLink](const TSharedPtr<FTextAndTooltip>& InEntry)
{
return InEntry.IsValid() && InEntry->Value == InPDGAssetLink->SelectedTOPNetworkIndex;
});
if (SelectedIndex < 0)
SelectedIndex = 0;
PDGTOPNetRow.ValueWidget.Widget =
SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
.Padding(2, 2, 5, 2)
.FillWidth(300.f)
.MaxWidth(300.f)
[
SAssignNew(ComboBoxTOPNet, SComboBox<TSharedPtr<FTextAndTooltip>>)
.OptionsSource(&TOPNetworksPtr)
.InitiallySelectedItem(TOPNetworksPtr[SelectedIndex])
.OnGenerateWidget_Lambda([](TSharedPtr<FTextAndTooltip> ChoiceEntry)
{
const FText ChoiceEntryText = FText::FromString(ChoiceEntry->Text);
const FText ChoiceEntryToolTip = FText::FromString(ChoiceEntry->ToolTip);
return SNew(STextBlock)
.Text(ChoiceEntryText)
.ToolTipText(ChoiceEntryToolTip)
.Margin(2.0f)
.Font(FEditorStyle::GetFontStyle(TEXT("PropertyWindow.NormalFont")));
})
.OnSelectionChanged_Lambda([OnTOPNetChanged](TSharedPtr<FTextAndTooltip> NewChoice, ESelectInfo::Type SelectType)
{
return OnTOPNetChanged(NewChoice);
})
[
SNew(STextBlock)
.Text_Lambda([InPDGAssetLink]()
{
return FText::FromString(InPDGAssetLink->GetSelectedTOPNetworkName());
})
.ToolTipText_Lambda([InPDGAssetLink]()
{
UTOPNetwork const * const Network = InPDGAssetLink->GetSelectedTOPNetwork();
if (IsValid(Network))
{
if (!Network->NodePath.IsEmpty())
return FText::FromString(Network->NodePath);
else
return FText::FromString(Network->NodeName);
}
else
{
return FText();
}
})
.Font(FEditorStyle::GetFontStyle(TEXT("PropertyWindow.NormalFont")))
]
];
}
// Buttons: DIRTY ALL / COOK OUTPUT
{
TSharedRef<SHorizontalBox> DirtyAllHBox = SNew(SHorizontalBox);
TSharedPtr<SHorizontalBox> CookOutHBox = SNew(SHorizontalBox);
FDetailWidgetRow& PDGDirtyCookRow = TOPNetWorkGrp.AddWidgetRow()
.WholeRowContent()
[
SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
.AutoWidth()
.VAlign(VAlign_Center)
.HAlign(HAlign_Center)
[
SNew(SBox)
.WidthOverride(200.0f)
[
SNew(SButton)
//.Text(LOCTEXT("DirtyAll", "Dirty All"))
.ToolTipText(LOCTEXT("DirtyAllTooltip", "Dirty all TOP nodes in the selected TOP network and clears all of its work item results."))
.ContentPadding(FMargin(5.0f, 5.0f))
.VAlign(VAlign_Center)
.HAlign(HAlign_Center)
.IsEnabled_Lambda([InPDGAssetLink]() { return IsPDGLinked(InPDGAssetLink) || (IsValid(InPDGAssetLink) && InPDGAssetLink->GetSelectedTOPNetwork()); })
.OnClicked_Lambda([InPDGAssetLink]()
{
if (IsValid(InPDGAssetLink))
{
UTOPNetwork* const TOPNetwork = InPDGAssetLink->GetSelectedTOPNetwork();
if (IsValid(TOPNetwork))
{
if (IsPDGLinked(InPDGAssetLink))
{
FHoudiniPDGManager::DirtyAll(TOPNetwork);
// FHoudiniPDGDetails::RefreshUI(InPDGAssetLink);
}
else
{
UHoudiniPDGAssetLink::ClearTOPNetworkWorkItemResults(TOPNetwork);
}
}
}
return FReply::Handled();
})
.Content()
[
SAssignNew(DirtyAllHBox, SHorizontalBox)
]
]
]
+ SHorizontalBox::Slot()
.AutoWidth()
[
SNew(SBox)
.WidthOverride(200.0f)
[
SNew(SButton)
//.Text(LOCTEXT("CookOut", "Cook Output"))
.ToolTipText(LOCTEXT("CookOutTooltip", "Cooks the output nodes of the selected TOP network"))
.ContentPadding(FMargin(5.0f, 5.0f))
.VAlign(VAlign_Center)
.HAlign(HAlign_Center)
.IsEnabled_Lambda([InPDGAssetLink]()
{
if (!IsPDGLinked(InPDGAssetLink))
return false;
const UTOPNetwork* const SelectedTOPNet = InPDGAssetLink->GetSelectedTOPNetwork();
if (!IsValid(SelectedTOPNet))
return false;
// Disable if there any nodes in the network that are already cooking
return !SelectedTOPNet->AnyWorkItemsPending();
})
.OnClicked_Lambda([InPDGAssetLink]()
{
if (IsValid(InPDGAssetLink->GetSelectedTOPNetwork()))
{
//InPDGAssetLink->WorkItemTally.ZeroAll();
FHoudiniPDGManager::CookOutput(InPDGAssetLink->GetSelectedTOPNetwork());
// FHoudiniPDGDetails::RefreshUI(InPDGAssetLink);
}
return FReply::Handled();
})
.Content()
[
SAssignNew(CookOutHBox, SHorizontalBox)
]
]
]
];
TSharedPtr<FSlateDynamicImageBrush> DirtyAllIconBrush = FHoudiniEngineEditor::Get().GetHoudiniEngineUIPDGDirtyAllIconBrush();
if (DirtyAllIconBrush.IsValid())
{
TSharedPtr<SImage> DirtyAllImage;
DirtyAllHBox->AddSlot()
.MaxWidth(16.0f)
[
SNew(SBox)
.WidthOverride(16.0f)
.HeightOverride(16.0f)
[
SAssignNew(DirtyAllImage, SImage)
]
];
DirtyAllImage->SetImage(
TAttribute<const FSlateBrush*>::Create(
TAttribute<const FSlateBrush*>::FGetter::CreateLambda([DirtyAllIconBrush]() { return DirtyAllIconBrush.Get(); })));
}
DirtyAllHBox->AddSlot()
.Padding(5.0, 0.0, 0.0, 0.0)
.VAlign(VAlign_Center)
.AutoWidth()
[
SNew(STextBlock)
.Text(LOCTEXT("DirtyAll", "Dirty All"))
];
TSharedPtr<FSlateDynamicImageBrush> CookOutIconBrush = FHoudiniEngineEditor::Get().GetHoudiniEngineUIRecookIconBrush();
if (CookOutIconBrush.IsValid())
{
TSharedPtr<SImage> CookOutImage;
CookOutHBox->AddSlot()
.MaxWidth(16.0f)
[
SNew(SBox)
.WidthOverride(16.0f)
.HeightOverride(16.0f)
[
SAssignNew(CookOutImage, SImage)
]
];
CookOutImage->SetImage(
TAttribute<const FSlateBrush*>::Create(
TAttribute<const FSlateBrush*>::FGetter::CreateLambda([CookOutIconBrush]() { return CookOutIconBrush.Get(); })));
}
CookOutHBox->AddSlot()
.Padding(5.0, 0.0, 0.0, 0.0)
.VAlign(VAlign_Center)
.AutoWidth()
[
SNew(STextBlock)
.Text(LOCTEXT("CookOut", "Cook Output"))
];
DisableIfPDGNotLinked(PDGDirtyCookRow, InPDGAssetLink);
}
// Buttons: PAUSE COOK / CANCEL COOK
{
TSharedRef<SHorizontalBox> PauseHBox = SNew(SHorizontalBox);
TSharedPtr<SHorizontalBox> CancelHBox = SNew(SHorizontalBox);
FDetailWidgetRow& PDGDirtyCookRow = TOPNetWorkGrp.AddWidgetRow()
.WholeRowContent()
[
SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
.AutoWidth()
[
SNew(SBox)
.WidthOverride(200.0f)
[
SNew(SButton)
//.Text(LOCTEXT("Pause", "Pause Cook"))
.ToolTipText(LOCTEXT("PauseTooltip", "Pauses cooking for the selected TOP Network"))
.ContentPadding(FMargin(5.0f, 2.0f))
.VAlign(VAlign_Center)
.HAlign(HAlign_Center)
.IsEnabled_Lambda([InPDGAssetLink]() { return IsPDGLinked(InPDGAssetLink); })
.OnClicked_Lambda([InPDGAssetLink]()
{
if (IsValid(InPDGAssetLink->GetSelectedTOPNetwork()))
{
//InPDGAssetLink->WorkItemTally.ZeroAll();
FHoudiniPDGManager::PauseCook(InPDGAssetLink->GetSelectedTOPNetwork());
// FHoudiniPDGDetails::RefreshUI(InPDGAssetLink);
}
return FReply::Handled();
})
.Content()
[
SAssignNew(PauseHBox, SHorizontalBox)
]
]
]
+ SHorizontalBox::Slot()
.AutoWidth()
[
SNew(SBox)
.WidthOverride(200.0f)
[
SNew(SButton)
//.Text(LOCTEXT("Cancel", "Cancel Cook"))
.ToolTipText(LOCTEXT("CancelTooltip", "Cancels cooking the selected TOP network"))
.ContentPadding(FMargin(5.0f, 2.0f))
.VAlign(VAlign_Center)
.HAlign(HAlign_Center)
.IsEnabled_Lambda([InPDGAssetLink]() { return IsPDGLinked(InPDGAssetLink); })
.OnClicked_Lambda([InPDGAssetLink]()
{
if (IsValid(InPDGAssetLink->GetSelectedTOPNetwork()))
{
//InPDGAssetLink->WorkItemTally.ZeroAll();
FHoudiniPDGManager::CancelCook(InPDGAssetLink->GetSelectedTOPNetwork());
// FHoudiniPDGDetails::RefreshUI(InPDGAssetLink);
}
return FReply::Handled();
})
.Content()
[
SAssignNew(CancelHBox, SHorizontalBox)
]
]
]
];
TSharedPtr<FSlateDynamicImageBrush> PauseIconBrush = FHoudiniEngineEditor::Get().GetHoudiniEngineUIPDGPauseIconBrush();
if (PauseIconBrush.IsValid())
{
TSharedPtr<SImage> PauseImage;
PauseHBox->AddSlot()
.MaxWidth(16.0f)
[
SNew(SBox)
.WidthOverride(16.0f)
.HeightOverride(16.0f)
[
SAssignNew(PauseImage, SImage)
]
];
PauseImage->SetImage(
TAttribute<const FSlateBrush*>::Create(
TAttribute<const FSlateBrush*>::FGetter::CreateLambda([PauseIconBrush]() { return PauseIconBrush.Get(); })));
}
PauseHBox->AddSlot()
.Padding(5.0, 0.0, 0.0, 0.0)
.VAlign(VAlign_Center)
.AutoWidth()
[
SNew(STextBlock)
.Text(LOCTEXT("Pause", "Pause Cook"))
];
TSharedPtr<FSlateDynamicImageBrush> CancelIconBrush = FHoudiniEngineEditor::Get().GetHoudiniEngineUIPDGCancelIconBrush();
if (CancelIconBrush.IsValid())
{
TSharedPtr<SImage> CancelImage;
CancelHBox->AddSlot()
.MaxWidth(16.0f)
[
SNew(SBox)
.WidthOverride(16.0f)
.HeightOverride(16.0f)
[
SAssignNew(CancelImage, SImage)
]
];
CancelImage->SetImage(
TAttribute<const FSlateBrush*>::Create(
TAttribute<const FSlateBrush*>::FGetter::CreateLambda([CancelIconBrush]() { return CancelIconBrush.Get(); })));
}
CancelHBox->AddSlot()
.Padding(5.0, 0.0, 0.0, 0.0)
.VAlign(VAlign_Center)
.AutoWidth()
[
SNew(STextBlock)
.Text(LOCTEXT("Cancel", "Cancel Cook"))
];
DisableIfPDGNotLinked(PDGDirtyCookRow, InPDGAssetLink);
}
// Buttons: Unload Work Item Objects
{
FDetailWidgetRow& PDGUnloadLoadWorkItemsRow = TOPNetWorkGrp.AddWidgetRow()
.WholeRowContent()
[
SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
.AutoWidth()
[
SNew(SBox)
.IsEnabled_Lambda([InPDGAssetLink]() { return IsValid(InPDGAssetLink) && InPDGAssetLink->GetSelectedTOPNetwork(); })
.WidthOverride(200.0f)
[
SNew(SButton)
.Text(LOCTEXT("UnloadWorkItemsForNetwork", "Unload All Work Item Objects"))
.ToolTipText(LOCTEXT("UnloadWorkItemsForNetworkTooltip", "Unloads / removes loaded work item results from level for all nodes in this network. Not undoable: use the \"Load Work Item Objects\" button on the individual TOP nodes to reload work item results."))
.ContentPadding(FMargin(5.0f, 2.0f))
.VAlign(VAlign_Center)
.HAlign(HAlign_Center)
.IsEnabled_Lambda([InPDGAssetLink]()
{
if (!IsValid(InPDGAssetLink))
return false;
UTOPNetwork* const SelectedNet = InPDGAssetLink->GetSelectedTOPNetwork();
if (!IsValid(SelectedNet) ||
INDEX_NONE == SelectedNet->AllTOPNodes.IndexOfByPredicate([](const UTOPNode* InNode) { return IsValid(InNode) && InNode->bCachedHaveLoadedWorkResults; }))
return false;
return true;
})
.OnClicked_Lambda([InPDGAssetLink]()
{
if (IsValid(InPDGAssetLink))
{
UTOPNetwork* const TOPNet = InPDGAssetLink->GetSelectedTOPNetwork();
if (IsValid(TOPNet))
{
if (IsPDGLinked(InPDGAssetLink))
{
// Set the state to ToDelete, PDGManager will delete it when processing work items
TOPNet->SetLoadedWorkResultsToDelete();
}
else
{
// Delete and unload the result objects and actors now
TOPNet->DeleteWorkResultOutputObjects();
}
}
}
return FReply::Handled();
})
]
]
];
}
// TOP NODE WIDGETS
FHoudiniPDGDetails::AddTOPNodeWidget(TOPNetWorkGrp, InPDGAssetLink);
}
bool
FHoudiniPDGDetails::GetSelectedTOPNodeStatusAndColor(UHoudiniPDGAssetLink* InPDGAssetLink, FString& OutTOPNodeStatus, FLinearColor &OutTOPNodeStatusColor)
{
OutTOPNodeStatus = FString();
OutTOPNodeStatusColor = FLinearColor::White;
if (IsValid(InPDGAssetLink))
{
UTOPNode* const TOPNode = InPDGAssetLink->GetSelectedTOPNode();
if (IsValid(TOPNode) && !TOPNode->bHidden)
{
OutTOPNodeStatus = UHoudiniPDGAssetLink::GetTOPNodeStatus(TOPNode);
OutTOPNodeStatusColor = UHoudiniPDGAssetLink::GetTOPNodeStatusColor(TOPNode);
return true;
}
}
return false;
}
void
FHoudiniPDGDetails::AddTOPNodeWidget(
IDetailGroup& InGroup, UHoudiniPDGAssetLink* InPDGAssetLink )
{
if (!InPDGAssetLink->GetSelectedTOPNetwork())
return;
FString GroupLabel = TEXT("TOP Nodes");
IDetailGroup& TOPNodesGrp = InGroup.AddGroup(FName(*GroupLabel), FText::FromString(GroupLabel), true);
// Combobox: TOP Node
{
FDetailWidgetRow& PDGTOPNodeRow = TOPNodesGrp.AddWidgetRow();
// DisableIfPDGNotLinked(PDGTOPNodeRow, InPDGAssetLink);
PDGTOPNodeRow.NameWidget.Widget =
SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
[
SNew(STextBlock)
.Text(FText::FromString(TEXT("TOP Node")))
];
// Update the TOP Node SharedString
TOPNodesPtr.Reset();
TOPNodesPtr.Add(MakeShareable(new FTextAndTooltip(INDEX_NONE, LOCTEXT("ComboBoxEntryNoSelectedTOPNode", "- Select -").ToString())));
const UTOPNetwork* const SelectedTOPNet = InPDGAssetLink->GetSelectedTOPNetwork();
if (IsValid(SelectedTOPNet))
{
const int32 NumTOPNodes = SelectedTOPNet->AllTOPNodes.Num();
for (int32 Idx = 0; Idx < NumTOPNodes; Idx++)
{
const UTOPNode* const Node = SelectedTOPNet->AllTOPNodes[Idx];
if (!IsValid(Node) || Node->bHidden)
continue;
TOPNodesPtr.Add(MakeShareable(new FTextAndTooltip(
Idx,
FHoudiniEngineEditorUtils::GetNodeNamePaddedByPathDepth(Node->NodeName, Node->NodePath),
Node->NodePath
)));
}
}
FString NodeErrorText = FString();
FString NodeErrorTooltip = FString();
FLinearColor NodeErrorColor = FLinearColor::White;
if (!IsValid(SelectedTOPNet) || SelectedTOPNet->AllTOPNodes.Num() <= 0)
{
NodeErrorText = TEXT("No valid TOP Node found!");
NodeErrorTooltip = TEXT("There is no valid TOP Node found in the selected TOP Network!");
NodeErrorColor = FLinearColor::Red;
}
else if(TOPNodesPtr.Num() <= 0)
{
NodeErrorText = TEXT("No visible TOP Node found!");
NodeErrorTooltip = TEXT("No visible TOP Node found, all nodes in this network are hidden. Please update your TOP Node Filter.");
NodeErrorColor = FLinearColor::Yellow;
}
// Lambda for selecting a TOPNode
auto OnTOPNodeChanged = [InPDGAssetLink](TSharedPtr<FTextAndTooltip> InNewChoice)
{
UTOPNetwork* const TOPNetwork = InPDGAssetLink->GetSelectedTOPNetwork();
if (!InNewChoice.IsValid() || !IsValid(TOPNetwork))
return;
const int32 NewChoice = InNewChoice->Value;
int32 NewSelectedIndex = INDEX_NONE;
if (TOPNetwork->AllTOPNodes.IsValidIndex(NewChoice))
NewSelectedIndex = NewChoice;
if (TOPNetwork->SelectedTOPIndex != NewSelectedIndex)
{
// Record a transaction for undo/redo
FScopedTransaction Transaction(
TEXT(HOUDINI_MODULE_RUNTIME),
LOCTEXT("HoudiniPDGAssetLinkParameterChange", "Houdini PDG Asset Link Parameter: Changing a value"),
TOPNetwork);
TOPNetwork->Modify();
TOPNetwork->SelectedTOPIndex = NewSelectedIndex;
FHoudiniEngineEditorUtils::NotifyPostEditChangeProperty(
GET_MEMBER_NAME_STRING_CHECKED(UTOPNetwork, SelectedTOPIndex), TOPNetwork);
}
};
TSharedPtr<SHorizontalBox, ESPMode::NotThreadSafe> HorizontalBoxTOPNode;
TSharedPtr<SComboBox<TSharedPtr<FTextAndTooltip>>> ComboBoxTOPNode;
int32 SelectedIndex = 0;
UTOPNetwork* const SelectedTOPNetwork = InPDGAssetLink->GetSelectedTOPNetwork();
if (IsValid(SelectedTOPNetwork) && SelectedTOPNetwork->SelectedTOPIndex >= 0)
{
//SelectedIndex = InPDGAssetLink->GetSelectedTOPNetwork()->SelectedTOPIndex;
// We need to match the selection by the index in the AllTopNodes array
// Because of the nodefilter, it is possible that the selected index does not match the index in TOPNodesPtr
const int32 SelectedTOPNodeIndex = SelectedTOPNetwork->SelectedTOPIndex;
// Find the matching UI index
for (int32 UIIndex = 0; UIIndex < TOPNodesPtr.Num(); UIIndex++)
{
if (TOPNodesPtr[UIIndex] && TOPNodesPtr[UIIndex]->Value == SelectedTOPNodeIndex)
{
// We found the UI Index that matches the current TOP Node!
SelectedIndex = UIIndex;
break;
}
}
}
TSharedPtr<STextBlock> ErrorText;
PDGTOPNodeRow.ValueWidget.Widget =
SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
.Padding(2, 2, 5, 2)
.FillWidth(300.f)
.MaxWidth(300.f)
[
SAssignNew(ComboBoxTOPNode, SComboBox<TSharedPtr<FTextAndTooltip>>)
.OptionsSource(&TOPNodesPtr)
.InitiallySelectedItem(TOPNodesPtr[SelectedIndex])
.OnGenerateWidget_Lambda([](TSharedPtr<FTextAndTooltip> ChoiceEntry)
{
const FText ChoiceEntryText = FText::FromString(ChoiceEntry->Text);
const FText ChoiceEntryToolTip = FText::FromString(ChoiceEntry->ToolTip);
return SNew(STextBlock)
.Text(ChoiceEntryText)
.ToolTipText(ChoiceEntryToolTip)
.Margin(2.0f)
.Font(FEditorStyle::GetFontStyle(TEXT("PropertyWindow.NormalFont")));
})
.OnSelectionChanged_Lambda([OnTOPNodeChanged](TSharedPtr<FTextAndTooltip> NewChoice, ESelectInfo::Type SelectType)
{
return OnTOPNodeChanged(NewChoice);
})
[
SNew(STextBlock)
.Text_Lambda([InPDGAssetLink, ComboBoxTOPNode, Options = TOPNodesPtr]()
{
if (IsValid(InPDGAssetLink))
return FText::FromString(InPDGAssetLink->GetSelectedTOPNodeName());
else
return FText();
})
.ToolTipText_Lambda([InPDGAssetLink]()
{
UTOPNode const * const TOPNode = InPDGAssetLink->GetSelectedTOPNode();
if (IsValid(TOPNode))
{
if (!TOPNode->NodePath.IsEmpty())
return FText::FromString(TOPNode->NodePath);
else
return FText::FromString(TOPNode->NodeName);
}
else
{
return FText();
}
})
.Font(FEditorStyle::GetFontStyle(TEXT("PropertyWindow.NormalFont")))
]
]
+ SHorizontalBox::Slot()
.Padding(2, 2, 5, 2)
.AutoWidth()
[
SAssignNew(ErrorText, STextBlock)
.Text(FText::FromString(NodeErrorText))
.ToolTipText(FText::FromString(NodeErrorText))
.Font(FEditorStyle::GetFontStyle(TEXT("PropertyWindow.NormalFont")))
.ColorAndOpacity(FLinearColor::Red)
//.ShadowColorAndOpacity(FLinearColor::Black)
];
// Update the error text if needed
ErrorText->SetText(FText::FromString(NodeErrorText));
ErrorText->SetToolTipText(FText::FromString(NodeErrorTooltip));
ErrorText->SetColorAndOpacity(NodeErrorColor);
// Hide the combobox if we have an error
ComboBoxTOPNode->SetVisibility(NodeErrorText.IsEmpty() ? EVisibility::Visible : EVisibility::Hidden);
}
// TOP Node State
{
FDetailWidgetRow& PDGNodeStateResultRow = TOPNodesGrp.AddWidgetRow();
DisableIfPDGNotLinked(PDGNodeStateResultRow, InPDGAssetLink);
PDGNodeStateResultRow.NameWidget.Widget =
SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
.AutoWidth()
.Padding(2.0f, 0.0f)
[
SNew(STextBlock)
.Text(FText::FromString(TEXT("TOP Node State")))
];
PDGNodeStateResultRow.ValueWidget.Widget =
SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
.AutoWidth()
.Padding(2.0f, 0.0f)
[
SNew(STextBlock)
.Text_Lambda([InPDGAssetLink]()
{
FString TOPNodeStatus = FString();
FLinearColor TOPNodeStatusColor = FLinearColor::White;
GetSelectedTOPNodeStatusAndColor(InPDGAssetLink, TOPNodeStatus, TOPNodeStatusColor);
return FText::FromString(TOPNodeStatus);
})
.ColorAndOpacity_Lambda([InPDGAssetLink]()
{
FString TOPNodeStatus = FString();
FLinearColor TOPNodeStatusColor = FLinearColor::White;
GetSelectedTOPNodeStatusAndColor(InPDGAssetLink, TOPNodeStatus, TOPNodeStatusColor);
return FSlateColor(TOPNodeStatusColor);
})
];
}
// Checkbox: Load Work Item Output Files
{
auto ToolTipLambda = [InPDGAssetLink]()
{
bool bDisabled = false;
if (IsValid(InPDGAssetLink) && InPDGAssetLink->GetSelectedTOPNode())
{
bDisabled = InPDGAssetLink->GetSelectedTOPNode()->bHasChildNodes;
}
return bDisabled
? FText::FromString(TEXT("This node has child nodes, the auto-load setting must be set on the child nodes individually."))
: FText::FromString(TEXT("When enabled, Output files produced by this TOP Node's Work Items will automatically be loaded when cooked."));
};
FDetailWidgetRow& PDGNodeAutoLoadRow = TOPNodesGrp.AddWidgetRow();
DisableIfPDGNotLinked(PDGNodeAutoLoadRow, InPDGAssetLink);
PDGNodeAutoLoadRow.IsEnabledAttr.Bind(TAttribute<bool>::FGetter::CreateLambda([InPDGAssetLink]()
{
if (!IsPDGLinked(InPDGAssetLink))
return false;
UTOPNode* const Node = InPDGAssetLink->GetSelectedTOPNode();
if (IsValid(Node) && !Node->bHidden && !Node->bHasChildNodes)
return true;
return false;
}));
PDGNodeAutoLoadRow.NameWidget.Widget =
SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
.AutoWidth()
.Padding(2.0f, 0.0f)
[
SNew(STextBlock)
.Text(FText::FromString(TEXT("Auto-Load Work Item Output Files")))
.ToolTipText_Lambda(ToolTipLambda)
];
TSharedPtr<SCheckBox> AutoLoadCheckBox;
PDGNodeAutoLoadRow.ValueWidget.Widget =
SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
.AutoWidth()
.Padding(2.0f, 0.0f)
[
// Checkbox
SAssignNew(AutoLoadCheckBox, SCheckBox)
.IsChecked_Lambda([InPDGAssetLink]()
{
return InPDGAssetLink->GetSelectedTOPNode()
? (InPDGAssetLink->GetSelectedTOPNode()->bAutoLoad ? ECheckBoxState::Checked : ECheckBoxState::Unchecked)
: ECheckBoxState::Unchecked;
})
.OnCheckStateChanged_Lambda([InPDGAssetLink](ECheckBoxState NewState)
{
const bool bNewState = (NewState == ECheckBoxState::Checked) ? true : false;
UTOPNode* TOPNode = InPDGAssetLink->GetSelectedTOPNode();
if (!IsValid(TOPNode) || TOPNode->bAutoLoad == bNewState)
return;
// Record a transaction for undo/redo
FScopedTransaction Transaction(
TEXT(HOUDINI_MODULE_RUNTIME),
LOCTEXT("HoudiniPDGAssetLinkParameterChange", "Houdini PDG Asset Link Parameter: Changing a value"),
TOPNode);
TOPNode->Modify();
TOPNode->bAutoLoad = bNewState;
FHoudiniEngineEditorUtils::NotifyPostEditChangeProperty(
GET_MEMBER_NAME_STRING_CHECKED(UTOPNode, bAutoLoad), TOPNode);
// FHoudiniPDGDetails::RefreshUI(InPDGAssetLink);
})
.ToolTipText_Lambda(ToolTipLambda)
];
}
// Checkbox: Work Item Output Files Visible
{
auto ToolTipLambda = [InPDGAssetLink]()
{
bool bDisabled = false;
if (IsValid(InPDGAssetLink) && InPDGAssetLink->GetSelectedTOPNode())
{
bDisabled = InPDGAssetLink->GetSelectedTOPNode()->bHasChildNodes;
}
return bDisabled
? FText::FromString(TEXT("This node has child nodes, visibility of work item outputs must be set on the child nodes individually."))
: FText::FromString(TEXT("Toggles the visibility of the actors created from this TOP Node's Work Item File Outputs."));
};
FDetailWidgetRow& PDGNodeShowResultRow = TOPNodesGrp.AddWidgetRow();
// DisableIfPDGNotLinked(PDGNodeShowResultRow, InPDGAssetLink);
PDGNodeShowResultRow.IsEnabledAttr.Bind(TAttribute<bool>::FGetter::CreateLambda([InPDGAssetLink]()
{
if (!IsValid(InPDGAssetLink))
return false;
UTOPNode* const Node = InPDGAssetLink->GetSelectedTOPNode();
if (IsValid(Node) && !Node->bHidden && !Node->bHasChildNodes)
return true;
return false;
}));
PDGNodeShowResultRow.NameWidget.Widget =
SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
.AutoWidth()
.Padding(2.0f, 0.0f)
[
SNew(STextBlock)
.Text(FText::FromString(TEXT("Work Item Output Files Visible")))
.ToolTipText_Lambda(ToolTipLambda)
];
TSharedPtr<SCheckBox> ShowResCheckBox;
PDGNodeShowResultRow.ValueWidget.Widget =
SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
.AutoWidth()
.Padding(2.0f, 0.0f)
[
// Checkbox
SAssignNew(ShowResCheckBox, SCheckBox)
.IsChecked_Lambda([InPDGAssetLink]()
{
return InPDGAssetLink->GetSelectedTOPNode()
? (InPDGAssetLink->GetSelectedTOPNode()->IsVisibleInLevel() ? ECheckBoxState::Checked : ECheckBoxState::Unchecked)
: ECheckBoxState::Unchecked;
})
.OnCheckStateChanged_Lambda([InPDGAssetLink](ECheckBoxState NewState)
{
const bool bNewState = (NewState == ECheckBoxState::Checked) ? true : false;
UTOPNode* const TOPNode = InPDGAssetLink->GetSelectedTOPNode();
if (!IsValid(TOPNode) || TOPNode->IsVisibleInLevel() == bNewState)
return;
// Record a transaction for undo/redo
FScopedTransaction Transaction(
TEXT(HOUDINI_MODULE_RUNTIME),
LOCTEXT("HoudiniPDGAssetLinkParameterChange", "Houdini PDG Asset Link Parameter: Changing a value"),
TOPNode);
TOPNode->Modify();
TOPNode->SetVisibleInLevel(bNewState);
FHoudiniEngineEditorUtils::NotifyPostEditChangeProperty(TEXT("bShow"), TOPNode);
// FHoudiniPDGDetails::RefreshUI(InPDGAssetLink);
})
.ToolTipText_Lambda(ToolTipLambda)
];
}
// Buttons: DIRTY NODE / COOK NODE
{
TSharedRef<SHorizontalBox> DirtyHBox = SNew(SHorizontalBox);
TSharedPtr<SHorizontalBox> CookHBox = SNew(SHorizontalBox);
TSharedPtr<SButton> DirtyButton;
TSharedPtr<SButton> CookButton;
FDetailWidgetRow& PDGDirtyCookRow = TOPNodesGrp.AddWidgetRow()
.WholeRowContent()
[
SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
.AutoWidth()
[
SNew(SBox)
.IsEnabled_Lambda([InPDGAssetLink]()
{
return IsPDGLinked(InPDGAssetLink) || (IsValid(InPDGAssetLink) && IsValid(InPDGAssetLink->GetSelectedTOPNode()));
})
.WidthOverride(200.0f)
[
SAssignNew(DirtyButton, SButton)
//.Text(LOCTEXT("DirtyNode", "Dirty Node"))
.ToolTipText(LOCTEXT("DirtyNodeTooltip", "Dirties the selected TOP node and clears its work item results."))
.ContentPadding(FMargin(5.0f, 2.0f))
.VAlign(VAlign_Center)
.HAlign(HAlign_Center)
.IsEnabled_Lambda([InPDGAssetLink]()
{
return IsPDGLinked(InPDGAssetLink) || (IsValid(InPDGAssetLink) && IsValid(InPDGAssetLink->GetSelectedTOPNode()));
})
.OnClicked_Lambda([InPDGAssetLink]()
{
if (IsValid(InPDGAssetLink))
{
UTOPNode* const TOPNode = InPDGAssetLink->GetSelectedTOPNode();
if (IsValid(TOPNode))
{
if (IsPDGLinked(InPDGAssetLink))
{
FHoudiniPDGManager::DirtyTOPNode(TOPNode);
// FHoudiniPDGDetails::RefreshUI(InPDGAssetLink);
}
else
{
UHoudiniPDGAssetLink::ClearTOPNodeWorkItemResults(TOPNode);
}
}
}
return FReply::Handled();
})
.IsEnabled_Lambda([InPDGAssetLink]()
{
if (IsValid(InPDGAssetLink->GetSelectedTOPNode()) && !InPDGAssetLink->GetSelectedTOPNode()->bHidden)
return true;
return false;
})
.Content()
[
SAssignNew(DirtyHBox, SHorizontalBox)
]
]
]
// + SHorizontalBox::Slot()
// .AutoWidth()
// [
// SNew(SBox)
// .WidthOverride(200.0f)
// [
// SAssignNew(DirtyButton, SButton)
// .Text(LOCTEXT("DirtyAllTasks", "Dirty All Tasks"))
// .ToolTipText(LOCTEXT("DirtyAllTasksTooltip", "Dirties all tasks/work items on the selected TOP node."))
// .ContentPadding(FMargin(5.0f, 2.0f))
// .VAlign(VAlign_Center)
// .HAlign(HAlign_Center)
// .OnClicked_Lambda([InPDGAssetLink]()
// {
// if(InPDGAssetLink->GetSelectedTOPNode())
// {
// FHoudiniPDGManager::DirtyAllTasksOfTOPNode(*(InPDGAssetLink->GetSelectedTOPNode()));
// FHoudiniPDGDetails::RefreshUI(InPDGAssetLink);
// }
//
// return FReply::Handled();
// })
// ]
// ]
+ SHorizontalBox::Slot()
.AutoWidth()
[
SNew(SBox)
.IsEnabled_Lambda([InPDGAssetLink]() { return IsPDGLinked(InPDGAssetLink); })
.WidthOverride(200.0f)
[
SAssignNew(CookButton, SButton)
//.Text(LOCTEXT("CookNode", "Cook Node"))
.ToolTipText(LOCTEXT("CookNodeTooltip", "Cooks the selected TOP Node."))
.ContentPadding(FMargin(5.0f, 2.0f))
.VAlign(VAlign_Center)
.HAlign(HAlign_Center)
.IsEnabled_Lambda([InPDGAssetLink]()
{
if (!IsPDGLinked(InPDGAssetLink))
return false;
UTOPNode* const SelectedNode = InPDGAssetLink->GetSelectedTOPNode();
if (!IsValid(SelectedNode))
return false;
// Disable Cook Node button if the node is already cooking
return !SelectedNode->bHidden && SelectedNode->NodeState != EPDGNodeState::Cooking && !SelectedNode->AnyWorkItemsPending();
})
.OnClicked_Lambda([InPDGAssetLink]()
{
UTOPNode* const Node = InPDGAssetLink->GetSelectedTOPNode();
if (IsValid(Node))
{
FHoudiniPDGManager::CookTOPNode(Node);
// FHoudiniPDGDetails::RefreshUI(InPDGAssetLink);
}
return FReply::Handled();
})
.Content()
[
SAssignNew(CookHBox, SHorizontalBox)
]
]
]
];
TSharedPtr<FSlateDynamicImageBrush> DirtyIconBrush = FHoudiniEngineEditor::Get().GetHoudiniEngineUIPDGDirtyNodeIconBrush();
if (DirtyIconBrush.IsValid())
{
TSharedPtr<SImage> DirtyImage;
DirtyHBox->AddSlot()
.MaxWidth(16.0f)
[
SNew(SBox)
.WidthOverride(16.0f)
.HeightOverride(16.0f)
[
SAssignNew(DirtyImage, SImage)
]
];
DirtyImage->SetImage(
TAttribute<const FSlateBrush*>::Create(
TAttribute<const FSlateBrush*>::FGetter::CreateLambda([DirtyIconBrush]() { return DirtyIconBrush.Get(); })));
}
DirtyHBox->AddSlot()
.Padding(5.0, 0.0, 0.0, 0.0)
.VAlign(VAlign_Center)
.AutoWidth()
[
SNew(STextBlock)
.Text(LOCTEXT("DirtyNode", "Dirty Node"))
];
TSharedPtr<FSlateDynamicImageBrush> CookIconBrush = FHoudiniEngineEditor::Get().GetHoudiniEngineUIRecookIconBrush();
if (CookIconBrush.IsValid())
{
TSharedPtr<SImage> CookImage;
CookHBox->AddSlot()
.MaxWidth(16.0f)
[
SNew(SBox)
.WidthOverride(16.0f)
.HeightOverride(16.0f)
[
SAssignNew(CookImage, SImage)
]
];
CookImage->SetImage(
TAttribute<const FSlateBrush*>::Create(
TAttribute<const FSlateBrush*>::FGetter::CreateLambda([CookIconBrush]() { return CookIconBrush.Get(); })));
}
CookHBox->AddSlot()
.Padding(5.0, 0.0, 0.0, 0.0)
.VAlign(VAlign_Center)
.AutoWidth()
[
SNew(STextBlock)
.Text(LOCTEXT("CookNode", "Cook Node"))
];
DisableIfPDGNotLinked(PDGDirtyCookRow, InPDGAssetLink);
}
// Buttons: Load Work Item Objects / Unload Work Item Objects
{
TSharedPtr<SButton> UnloadWorkItemsButton;
TSharedPtr<SButton> LoadWorkItemsButton;
FDetailWidgetRow& PDGUnloadLoadWorkItemsRow = TOPNodesGrp.AddWidgetRow()
.WholeRowContent()
[
SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
.AutoWidth()
[
SNew(SBox)
.IsEnabled_Lambda([InPDGAssetLink]()
{
return IsValid(InPDGAssetLink) && IsValid(InPDGAssetLink->GetSelectedTOPNode());
})
.WidthOverride(200.0f)
[
SAssignNew(UnloadWorkItemsButton, SButton)
.Text(LOCTEXT("UnloadWorkItemsForNode", "Unload Work Item Objects"))
.ToolTipText(LOCTEXT("UnloadWorkItemsForNodeTooltip", "Unloads / removes loaded work item results from level. Not undoable: use the \"Load Work Item Objects\" button to reload the results."))
.ContentPadding(FMargin(5.0f, 2.0f))
.VAlign(VAlign_Center)
.HAlign(HAlign_Center)
.IsEnabled_Lambda([InPDGAssetLink]()
{
if (!IsValid(InPDGAssetLink))
return false;
UTOPNode* const SelectedNode = InPDGAssetLink->GetSelectedTOPNode();
if (!IsValid(SelectedNode) || SelectedNode->bHidden || !SelectedNode->bCachedHaveLoadedWorkResults)
return false;
return true;
})
.OnClicked_Lambda([InPDGAssetLink]()
{
if (IsValid(InPDGAssetLink))
{
UTOPNode* const TOPNode = InPDGAssetLink->GetSelectedTOPNode();
if (IsValid(TOPNode))
{
if (IsPDGLinked(InPDGAssetLink))
{
// Set the state to ToDelete, PDGManager will delete it when processing work items
TOPNode->SetLoadedWorkResultsToDelete();
}
else
{
// Delete and unload the result objects and actors now
TOPNode->DeleteWorkResultOutputObjects();
}
}
}
return FReply::Handled();
})
]
]
+ SHorizontalBox::Slot()
.AutoWidth()
[
SNew(SBox)
.IsEnabled_Lambda([InPDGAssetLink]() { return IsPDGLinked(InPDGAssetLink); })
.WidthOverride(200.0f)
[
SAssignNew(LoadWorkItemsButton, SButton)
.Text(LOCTEXT("LoadWorkItems", "Load Work Item Objects"))
.ToolTipText(LOCTEXT("LoadWorkItemsForNodeTooltip", "Loads any available but not loaded work items objects (this could include items from a previous cook). Creates output actors. Not undoable: use the \"Unload Work Item Objects\" button to unload/remove loaded work item results."))
.ContentPadding(FMargin(5.0f, 2.0f))
.VAlign(VAlign_Center)
.HAlign(HAlign_Center)
.IsEnabled_Lambda([InPDGAssetLink]()
{
if (!IsValid(InPDGAssetLink))
return false;
UTOPNode* const SelectedNode = InPDGAssetLink->GetSelectedTOPNode();
if (!IsValid(SelectedNode) || SelectedNode->bHidden || !SelectedNode->bCachedHaveNotLoadedWorkResults)
return false;
return true;
})
.OnClicked_Lambda([InPDGAssetLink]()
{
if (IsValid(InPDGAssetLink))
{
UTOPNode* const SelectedNode = InPDGAssetLink->GetSelectedTOPNode();
if (IsValid(SelectedNode))
{
SelectedNode->SetNotLoadedWorkResultsToLoad(true);
}
}
return FReply::Handled();
})
]
]
];
}
// TOP Node WorkItem Status
{
if (InPDGAssetLink->GetSelectedTOPNode())
{
FDetailWidgetRow& PDGNodeWorkItemStatsRow = TOPNodesGrp.AddWidgetRow();
DisableIfPDGNotLinked(PDGNodeWorkItemStatsRow, InPDGAssetLink);
FHoudiniPDGDetails::AddWorkItemStatusWidget(
PDGNodeWorkItemStatsRow, TEXT("TOP Node Work Item Status"), InPDGAssetLink, true);
}
}
}
void
FHoudiniPDGDetails::RefreshPDGAssetLink(UHoudiniPDGAssetLink* InPDGAssetLink)
{
// Repopulate the network and nodes for the assetlink
if (!FHoudiniPDGManager::UpdatePDGAssetLink(InPDGAssetLink))
return;
FHoudiniPDGDetails::RefreshUI(InPDGAssetLink, true);
}
void
FHoudiniPDGDetails::RefreshUI(UHoudiniPDGAssetLink* InPDGAssetLink, const bool& InFullUpdate)
{
if (!InPDGAssetLink || InPDGAssetLink->IsPendingKill())
return;
// Update the workitem stats
InPDGAssetLink->UpdateWorkItemTally();
// Update the editor properties
FHoudiniEngineUtils::UpdateEditorProperties(InPDGAssetLink, InFullUpdate);
}
void
FHoudiniPDGDetails::CreatePDGBakeWidgets(IDetailCategoryBuilder& InPDGCategory, UHoudiniPDGAssetLink* InPDGAssetLink)
{
if (!InPDGAssetLink || InPDGAssetLink->IsPendingKill())
return;
FHoudiniEngineDetails::AddHeaderRowForHoudiniPDGAssetLink(InPDGCategory, InPDGAssetLink, HOUDINI_ENGINE_UI_SECTION_PDG_BAKE);
if (!InPDGAssetLink->bBakeMenuExpanded)
return;
auto OnBakeButtonClickedLambda = [InPDGAssetLink]()
{
switch (InPDGAssetLink->HoudiniEngineBakeOption)
{
case EHoudiniEngineBakeOption::ToActor:
{
// if (InPDGAssetLink->bIsReplace)
// FHoudiniEngineBakeUtils::ReplaceHoudiniActorWithActors(InPDGAssetLink);
// else
FHoudiniEngineBakeUtils::BakePDGAssetLinkOutputsKeepActors(InPDGAssetLink, InPDGAssetLink->PDGBakeSelectionOption, InPDGAssetLink->PDGBakePackageReplaceMode, InPDGAssetLink->bRecenterBakedActors);
}
break;
case EHoudiniEngineBakeOption::ToBlueprint:
{
// if (InPDGAssetLink->bIsReplace)
// FHoudiniEngineBakeUtils::ReplaceWithBlueprint(InPDGAssetLink);
// else
FHoudiniEngineBakeUtils::BakePDGAssetLinkBlueprints(InPDGAssetLink, InPDGAssetLink->PDGBakeSelectionOption, InPDGAssetLink->PDGBakePackageReplaceMode, InPDGAssetLink->bRecenterBakedActors);
}
break;
//
// case EHoudiniEngineBakeOption::ToFoliage:
// {
// if (InPDGAssetLink->bIsReplace)
// FHoudiniEngineBakeUtils::ReplaceHoudiniActorWithFoliage(InPDGAssetLink);
// else
// FHoudiniEngineBakeUtils::BakeHoudiniActorToFoliage(InPDGAssetLink);
// }
// break;
//
// case EHoudiniEngineBakeOption::ToWorldOutliner:
// {
// if (InPDGAssetLink->bIsReplace)
// {
// // Todo
// }
// else
// {
// //Todo
// }
// }
// break;
}
return FReply::Handled();
};
auto OnBakeFolderTextCommittedLambda = [InPDGAssetLink](const FText& Val, ETextCommit::Type TextCommitType)
{
FString NewPathStr = Val.ToString();
if (NewPathStr.IsEmpty())
return;
// Record a transaction for undo/redo
FScopedTransaction Transaction(
TEXT(HOUDINI_MODULE_RUNTIME),
LOCTEXT("HoudiniPDGAssetLinkParameterChange", "Houdini PDG Asset Link Parameter: Changing a value"),
InPDGAssetLink);
//Todo? Check if the new Bake folder path is valid
InPDGAssetLink->Modify();
InPDGAssetLink->BakeFolder.Path = NewPathStr;
FHoudiniEngineEditorUtils::NotifyPostEditChangeProperty(
GET_MEMBER_NAME_STRING_CHECKED(UHoudiniPDGAssetLink, BakeFolder), InPDGAssetLink);
};
// Button Row
FDetailWidgetRow & ButtonRow = InPDGCategory.AddCustomRow(FText::GetEmpty());
DisableIfPDGNotLinked(ButtonRow, InPDGAssetLink);
TSharedRef<SHorizontalBox> ButtonRowHorizontalBox = SNew(SHorizontalBox);
// Bake Button
TSharedRef<SHorizontalBox> BakeHBox = SNew(SHorizontalBox);
TSharedPtr<SButton> BakeButton;
ButtonRowHorizontalBox->AddSlot()
/*.AutoWidth()*/
.Padding(15.f, 0.0f, 0.0f, 0.0f)
.MaxWidth(75.0f)
[
SNew(SBox)
.WidthOverride(75.0f)
[
SAssignNew(BakeButton, SButton)
//.Text(FText::FromString("Bake"))
.VAlign(VAlign_Center)
.HAlign(HAlign_Center)
//.ToolTipText(LOCTEXT("HoudiniPDGDetailsBakeButton", "Bake the Houdini PDG TOP Node(s)"))
.ToolTipText_Lambda([InPDGAssetLink]()
{
switch (InPDGAssetLink->HoudiniEngineBakeOption)
{
case EHoudiniEngineBakeOption::ToActor:
{
return LOCTEXT(
"HoudiniEnginePDGBakeButtonBakeToActorToolTip",
"Bake this Houdini PDG Asset's output assets and seperate the output actors from the PDG asset link.");
}
break;
case EHoudiniEngineBakeOption::ToBlueprint:
{
return LOCTEXT(
"HoudiniEnginePDGBakeButtonBakeToBlueprintToolTip",
"Bake this Houdini PDG Asset's output assets to blueprints and remove temporary output actors that no "
"longer has output components from the PDG asset link.");
}
break;
default:
{
return FText();
}
}
})
.Visibility(EVisibility::Visible)
.IsEnabled_Lambda([InPDGAssetLink]() { return IsPDGLinked(InPDGAssetLink); })
.OnClicked_Lambda(OnBakeButtonClickedLambda)
.Content()
[
SAssignNew(BakeHBox, SHorizontalBox)
]
]
];
TSharedPtr<FSlateDynamicImageBrush> BakeIconBrush = FHoudiniEngineEditor::Get().GetHoudiniEngineUIBakeIconBrush();
if (BakeIconBrush.IsValid())
{
TSharedPtr<SImage> BakeImage;
BakeHBox->AddSlot()
.MaxWidth(16.0f)
[
SNew(SBox)
.WidthOverride(16.0f)
.HeightOverride(16.0f)
[
SAssignNew(BakeImage, SImage)
]
];
BakeImage->SetImage(
TAttribute<const FSlateBrush*>::Create(
TAttribute<const FSlateBrush*>::FGetter::CreateLambda([BakeIconBrush]() { return BakeIconBrush.Get(); })));
}
BakeHBox->AddSlot()
.Padding(5.0, 0.0, 0.0, 0.0)
.VAlign(VAlign_Center)
.AutoWidth()
[
SNew(STextBlock)
.Text(FText::FromString("Bake"))
];
// bake Type ComboBox
TSharedPtr<SComboBox<TSharedPtr<FString>>> TypeComboBox;
TArray<TSharedPtr<FString>>* OptionSource = FHoudiniEngineEditor::Get().GetHoudiniEnginePDGBakeTypeOptionsLabels();
TSharedPtr<FString> IntialSelec;
if (OptionSource)
{
// IntialSelec = (*OptionSource)[(int)InPDGAssetLink->HoudiniEngineBakeOption];
const FString DefaultStr = FHoudiniEngineEditor::Get().GetStringFromHoudiniEngineBakeOption(InPDGAssetLink->HoudiniEngineBakeOption);
const TSharedPtr<FString>* DefaultOption = OptionSource->FindByPredicate(
[DefaultStr](TSharedPtr<FString> InStringPtr)
{
return InStringPtr.IsValid() && *InStringPtr == DefaultStr;
}
);
if (DefaultOption)
IntialSelec = *DefaultOption;
}
ButtonRowHorizontalBox->AddSlot()
/*.AutoWidth()*/
.Padding(3.0, 0.0, 4.0f, 0.0f)
.MaxWidth(93.f)
[
SNew(SBox)
.IsEnabled_Lambda([InPDGAssetLink]() { return IsPDGLinked(InPDGAssetLink); })
.WidthOverride(93.f)
[
SAssignNew(TypeComboBox, SComboBox<TSharedPtr<FString>>)
.OptionsSource(OptionSource)
.InitiallySelectedItem(IntialSelec)
.OnGenerateWidget_Lambda(
[](TSharedPtr< FString > InItem)
{
FText ChoiceEntryText = FText::FromString(*InItem);
return SNew(STextBlock)
.Text(ChoiceEntryText)
.ToolTipText(ChoiceEntryText)
.Font(FEditorStyle::GetFontStyle(TEXT("PropertyWindow.NormalFont")));
})
.OnSelectionChanged_Lambda(
[InPDGAssetLink](TSharedPtr< FString > NewChoice, ESelectInfo::Type SelectType)
{
if (!NewChoice.IsValid() || SelectType == ESelectInfo::Type::Direct)
return;
const EHoudiniEngineBakeOption NewOption =
FHoudiniEngineEditor::Get().StringToHoudiniEngineBakeOption(*NewChoice.Get());
if (NewOption != InPDGAssetLink->HoudiniEngineBakeOption)
{
// Record a transaction for undo/redo
FScopedTransaction Transaction(
TEXT(HOUDINI_MODULE_RUNTIME),
LOCTEXT("HoudiniPDGAssetLinkParameterChange", "Houdini PDG Asset Link Parameter: Changing a value"),
InPDGAssetLink);
InPDGAssetLink->Modify();
InPDGAssetLink->HoudiniEngineBakeOption = NewOption;
FHoudiniEngineEditorUtils::NotifyPostEditChangeProperty(
GET_MEMBER_NAME_STRING_CHECKED(UHoudiniPDGAssetLink, HoudiniEngineBakeOption), InPDGAssetLink);
}
})
[
SNew(STextBlock)
.Text_Lambda([InPDGAssetLink, TypeComboBox, OptionSource]()
{
return FText::FromString(FHoudiniEngineEditor::Get().GetStringFromHoudiniEngineBakeOption(InPDGAssetLink->HoudiniEngineBakeOption));
})
.Font(FEditorStyle::GetFontStyle(TEXT("PropertyWindow.NormalFont")))
]
]
];
// bake selection ComboBox
TSharedPtr<SComboBox<TSharedPtr<FString>>> BakeSelectionComboBox;
TArray<TSharedPtr<FString>>* PDGBakeSelectionOptionSource = FHoudiniEngineEditor::Get().GetHoudiniEnginePDGBakeSelectionOptionsLabels();
TSharedPtr<FString> PDGBakeSelectionIntialSelec;
if (PDGBakeSelectionOptionSource)
{
PDGBakeSelectionIntialSelec = (*PDGBakeSelectionOptionSource)[(int)InPDGAssetLink->PDGBakeSelectionOption];
}
ButtonRowHorizontalBox->AddSlot()
/*.AutoWidth()*/
.Padding(3.0, 0.0, 4.0f, 0.0f)
.MaxWidth(163.f)
[
SNew(SBox)
.IsEnabled_Lambda([InPDGAssetLink]() { return IsPDGLinked(InPDGAssetLink); })
.WidthOverride(163.f)
[
SAssignNew(TypeComboBox, SComboBox<TSharedPtr<FString>>)
.OptionsSource(PDGBakeSelectionOptionSource)
.InitiallySelectedItem(PDGBakeSelectionIntialSelec)
.OnGenerateWidget_Lambda(
[](TSharedPtr< FString > InItem)
{
FText ChoiceEntryText = FText::FromString(*InItem);
return SNew(STextBlock)
.Text(ChoiceEntryText)
.ToolTipText(ChoiceEntryText)
.Font(FEditorStyle::GetFontStyle(TEXT("PropertyWindow.NormalFont")));
})
.OnSelectionChanged_Lambda(
[InPDGAssetLink](TSharedPtr< FString > NewChoice, ESelectInfo::Type SelectType)
{
if (!NewChoice.IsValid())
return;
const EPDGBakeSelectionOption NewOption =
FHoudiniEngineEditor::Get().StringToPDGBakeSelectionOption(*NewChoice.Get());
if (NewOption != InPDGAssetLink->PDGBakeSelectionOption)
{
// Record a transaction for undo/redo
FScopedTransaction Transaction(
TEXT(HOUDINI_MODULE_RUNTIME),
LOCTEXT("HoudiniPDGAssetLinkParameterChange", "Houdini PDG Asset Link Parameter: Changing a value"),
InPDGAssetLink);
InPDGAssetLink->Modify();
InPDGAssetLink->PDGBakeSelectionOption = NewOption;
FHoudiniEngineEditorUtils::NotifyPostEditChangeProperty(
GET_MEMBER_NAME_STRING_CHECKED(UHoudiniPDGAssetLink, PDGBakeSelectionOption), InPDGAssetLink);
}
})
[
SNew(STextBlock)
.Text_Lambda([InPDGAssetLink]()
{
return FText::FromString(
FHoudiniEngineEditor::Get().GetStringFromPDGBakeTargetOption(InPDGAssetLink->PDGBakeSelectionOption));
})
.Font(FEditorStyle::GetFontStyle(TEXT("PropertyWindow.NormalFont")))
]
]
];
ButtonRow.WholeRowWidget.Widget = ButtonRowHorizontalBox;
// Bake package replacement mode row
FDetailWidgetRow & BakePackageReplaceRow = InPDGCategory.AddCustomRow(FText::GetEmpty());
DisableIfPDGNotLinked(BakePackageReplaceRow, InPDGAssetLink);
TSharedRef<SHorizontalBox> BakePackageReplaceRowHorizontalBox = SNew(SHorizontalBox);
BakePackageReplaceRowHorizontalBox->AddSlot()
/*.AutoWidth()*/
.Padding(30.0f, 0.0f, 6.0f, 0.0f)
.MaxWidth(155.0f)
[
SNew(SBox)
.IsEnabled_Lambda([InPDGAssetLink]() { return IsPDGLinked(InPDGAssetLink); })
.WidthOverride(155.0f)
[
SNew(STextBlock)
.Text(LOCTEXT("HoudiniEnginePDGBakePackageReplacementModeLabel", "Replace Mode"))
.ToolTipText(
LOCTEXT("HoudiniEnginePDGBakePackageReplacementModeTooltip", "Replacement mode "
"during baking. Create new assets, using numerical suffixes in package names when necessary, or "
"replace existing assets with matching names. Also replaces the previous bake's output actors in "
"replacement mode vs creating incremental ones."))
]
];
// bake package replace mode ComboBox
TSharedPtr<SComboBox<TSharedPtr<FString>>> BakePackageReplaceModeComboBox;
TArray<TSharedPtr<FString>>* PDGBakePackageReplaceModeOptionSource = FHoudiniEngineEditor::Get().GetHoudiniEnginePDGBakePackageReplaceModeOptionsLabels();
TSharedPtr<FString> PDGBakePackageReplaceModeInitialSelec;
if (PDGBakePackageReplaceModeOptionSource)
{
const FString DefaultStr = FHoudiniEngineEditor::Get().GetStringFromPDGBakePackageReplaceModeOption(InPDGAssetLink->PDGBakePackageReplaceMode);
const TSharedPtr<FString>* DefaultOption = PDGBakePackageReplaceModeOptionSource->FindByPredicate(
[DefaultStr](TSharedPtr<FString> InStringPtr)
{
return InStringPtr.IsValid() && *InStringPtr == DefaultStr;
}
);
if (DefaultOption)
PDGBakePackageReplaceModeInitialSelec = *DefaultOption;
}
BakePackageReplaceRowHorizontalBox->AddSlot()
/*.AutoWidth()*/
.Padding(3.0, 0.0, 4.0f, 0.0f)
.MaxWidth(163.f)
[
SNew(SBox)
.IsEnabled_Lambda([InPDGAssetLink]() { return IsPDGLinked(InPDGAssetLink); })
.WidthOverride(163.f)
[
SAssignNew(TypeComboBox, SComboBox<TSharedPtr<FString>>)
.OptionsSource(PDGBakePackageReplaceModeOptionSource)
.InitiallySelectedItem(PDGBakePackageReplaceModeInitialSelec)
.OnGenerateWidget_Lambda(
[](TSharedPtr< FString > InItem)
{
const FText ChoiceEntryText = FText::FromString(*InItem);
return SNew(STextBlock)
.Text(ChoiceEntryText)
.ToolTipText(ChoiceEntryText)
.Font(FEditorStyle::GetFontStyle(TEXT("PropertyWindow.NormalFont")));
})
.OnSelectionChanged_Lambda(
[InPDGAssetLink](TSharedPtr< FString > NewChoice, ESelectInfo::Type SelectType)
{
if (!NewChoice.IsValid())
return;
const EPDGBakePackageReplaceModeOption NewOption =
FHoudiniEngineEditor::Get().StringToPDGBakePackageReplaceModeOption(*NewChoice.Get());
if (NewOption != InPDGAssetLink->PDGBakePackageReplaceMode)
{
// Record a transaction for undo/redo
FScopedTransaction Transaction(
TEXT(HOUDINI_MODULE_RUNTIME),
LOCTEXT("HoudiniPDGAssetLinkParameterChange", "Houdini PDG Asset Link Parameter: Changing a value"),
InPDGAssetLink);
InPDGAssetLink->Modify();
InPDGAssetLink->PDGBakePackageReplaceMode = NewOption;
FHoudiniEngineEditorUtils::NotifyPostEditChangeProperty(
GET_MEMBER_NAME_STRING_CHECKED(UHoudiniPDGAssetLink, PDGBakePackageReplaceMode), InPDGAssetLink);
}
})
[
SNew(STextBlock)
.Text_Lambda([InPDGAssetLink]()
{
return FText::FromString(
FHoudiniEngineEditor::Get().GetStringFromPDGBakePackageReplaceModeOption(InPDGAssetLink->PDGBakePackageReplaceMode));
})
.Font(FEditorStyle::GetFontStyle(TEXT("PropertyWindow.NormalFont")))
]
]
];
BakePackageReplaceRow.WholeRowWidget.Widget = BakePackageReplaceRowHorizontalBox;
// Bake Folder Row
FDetailWidgetRow & BakeFolderRow = InPDGCategory.AddCustomRow(FText::GetEmpty());
DisableIfPDGNotLinked(BakeFolderRow, InPDGAssetLink);
TSharedRef<SHorizontalBox> BakeFolderRowHorizontalBox = SNew(SHorizontalBox);
BakeFolderRowHorizontalBox->AddSlot()
/*.AutoWidth()*/
.Padding(30.0f, 0.0f, 6.0f, 0.0f)
.MaxWidth(155.0f)
[
SNew(SBox)
.IsEnabled_Lambda([InPDGAssetLink]() { return IsPDGLinked(InPDGAssetLink); })
.WidthOverride(155.0f)
[
SNew(STextBlock)
.Text(LOCTEXT("HoudiniEngineBakeFolderLabel", "Bake Folder"))
.ToolTipText(LOCTEXT(
"HoudiniEnginePDGBakeFolderTooltip",
"The folder used to store the objects that are generated by this Houdini PDG Asset when baking, if the "
"unreal_bake_folder attribute is not set on the geometry. If this value is blank, the default from the "
"plugin settings is used."))
]
];
BakeFolderRowHorizontalBox->AddSlot()
/*.AutoWidth()*/
.MaxWidth(235.0)
[
SNew(SBox)
.IsEnabled_Lambda([InPDGAssetLink]() { return IsPDGLinked(InPDGAssetLink); })
.WidthOverride(235.0f)
[
SNew(SEditableTextBox)
.MinDesiredWidth(HAPI_UNREAL_DESIRED_ROW_VALUE_WIDGET_WIDTH)
.ToolTipText(LOCTEXT(
"HoudiniEnginePDGBakeFolderTooltip",
"The folder used to store the objects that are generated by this Houdini PDG Asset when baking, if the "
"unreal_bake_folder attribute is not set on the geometry. If this value is blank, the default from the "
"plugin settings is used."))
.HintText(LOCTEXT("HoudiniEngineBakeFolderHintText", "Input to set bake folder"))
.Font(FEditorStyle::GetFontStyle(TEXT("PropertyWindow.NormalFont")))
.Text_Lambda([InPDGAssetLink](){ return FText::FromString(InPDGAssetLink->BakeFolder.Path); })
.OnTextCommitted_Lambda(OnBakeFolderTextCommittedLambda)
]
];
BakeFolderRow.WholeRowWidget.Widget = BakeFolderRowHorizontalBox;
// Add additional bake options
FDetailWidgetRow & AdditionalBakeSettingsRow = InPDGCategory.AddCustomRow(FText::GetEmpty());
TSharedRef<SHorizontalBox> AdditionalBakeSettingsRowHorizontalBox = SNew(SHorizontalBox);
TSharedPtr<SCheckBox> CheckBoxAutoBake;
TSharedPtr<SCheckBox> CheckBoxRecenterBakedActors;
TSharedPtr<SVerticalBox> LeftColumnVerticalBox;
TSharedPtr<SVerticalBox> RightColumnVerticalBox;
AdditionalBakeSettingsRowHorizontalBox->AddSlot()
.Padding(30.0f, 5.0f, 0.0f, 0.0f)
.MaxWidth(200.f)
[
SNew(SBox)
.WidthOverride(200.f)
[
SAssignNew(LeftColumnVerticalBox, SVerticalBox)
]
];
AdditionalBakeSettingsRowHorizontalBox->AddSlot()
.Padding(20.0f, 5.0f, 0.0f, 0.0f)
.MaxWidth(200.f)
[
SNew(SBox)
[
SAssignNew(RightColumnVerticalBox, SVerticalBox)
]
];
LeftColumnVerticalBox->AddSlot()
.AutoHeight()
.Padding(0.0f, 0.0f, 0.0f, 3.5f)
[
SNew(SBox)
.WidthOverride(160.f)
[
SAssignNew(CheckBoxRecenterBakedActors, SCheckBox)
.Content()
[
SNew(STextBlock).Text(LOCTEXT("HoudiniEngineUIRecenterBakedActorsCheckBox", "Recenter Baked Actors"))
.ToolTipText(LOCTEXT("HoudiniEngineUIRecenterBakedActorsCheckBoxToolTip", "After baking recenter the baked actors to their bounding box center."))
.Font(FEditorStyle::GetFontStyle(TEXT("PropertyWindow.NormalFont")))
]
.IsChecked_Lambda([InPDGAssetLink]()
{
return InPDGAssetLink->bRecenterBakedActors ? ECheckBoxState::Checked : ECheckBoxState::Unchecked;
})
.OnCheckStateChanged_Lambda([InPDGAssetLink](ECheckBoxState NewState)
{
const bool bNewState = (NewState == ECheckBoxState::Checked);
// Record a transaction for undo/redo
FScopedTransaction Transaction(
TEXT(HOUDINI_MODULE_RUNTIME),
LOCTEXT("HoudiniPDGAssetLinkParameterChange", "Houdini PDG Asset Link Parameter: Changing a value"),
InPDGAssetLink);
InPDGAssetLink->Modify();
InPDGAssetLink->bRecenterBakedActors = bNewState;
// Notify that we have changed the property
FHoudiniEngineEditorUtils::NotifyPostEditChangeProperty(
GET_MEMBER_NAME_STRING_CHECKED(UHoudiniPDGAssetLink, bRecenterBakedActors), InPDGAssetLink);
})
]
];
RightColumnVerticalBox->AddSlot()
.AutoHeight()
.Padding(0.0f, 0.0f, 0.0f, 3.5f)
[
SNew(SBox)
.WidthOverride(160.f)
[
SAssignNew(CheckBoxAutoBake, SCheckBox)
.Content()
[
SNew(STextBlock).Text(LOCTEXT("HoudiniEngineUIAutoBakeCheckBox", "Auto Bake"))
.ToolTipText(LOCTEXT("HoudiniEngineUIAutoBakeCheckBoxToolTip", "Automatically bake work result object as they are loaded."))
.Font(FEditorStyle::GetFontStyle(TEXT("PropertyWindow.NormalFont")))
]
.IsChecked_Lambda([InPDGAssetLink]()
{
return InPDGAssetLink->bBakeAfterAllWorkResultObjectsLoaded ? ECheckBoxState::Checked : ECheckBoxState::Unchecked;
})
.OnCheckStateChanged_Lambda([InPDGAssetLink](ECheckBoxState NewState)
{
const bool bNewState = (NewState == ECheckBoxState::Checked);
if (!InPDGAssetLink || InPDGAssetLink->IsPendingKill())
return;
// Record a transaction for undo/redo
FScopedTransaction Transaction(
TEXT(HOUDINI_MODULE_RUNTIME),
LOCTEXT("HoudiniPDGAssetLinkParameterChange", "Houdini PDG Asset Link Parameter: Changing a value"),
InPDGAssetLink);
InPDGAssetLink->Modify();
InPDGAssetLink->bBakeAfterAllWorkResultObjectsLoaded = bNewState;
// Notify that we have changed the property
FHoudiniEngineEditorUtils::NotifyPostEditChangeProperty(
GET_MEMBER_NAME_STRING_CHECKED(UHoudiniPDGAssetLink, bBakeAfterAllWorkResultObjectsLoaded), InPDGAssetLink);
})
]
];
AdditionalBakeSettingsRow.WholeRowWidget.Widget = AdditionalBakeSettingsRowHorizontalBox;
}
FTextAndTooltip::FTextAndTooltip(int32 InValue, const FString& InText)
: Text(InText)
, Value(InValue)
{
}
FTextAndTooltip::FTextAndTooltip(int32 InValue, const FString& InText, const FString &InToolTip)
: Text(InText)
, ToolTip(InToolTip)
, Value(InValue)
{
}
FTextAndTooltip::FTextAndTooltip(int32 InValue, FString&& InText)
: Text(InText)
, Value(InValue)
{
}
FTextAndTooltip::FTextAndTooltip(int32 InValue, FString&& InText, FString&& InToolTip)
: Text(InText)
, ToolTip(InToolTip)
, Value(InValue)
{
}
#undef LOCTEXT_NAMESPACE