// Copyright Epic Games, Inc. All Rights Reserved. #include "SNewLevelInstanceDialog.h" #include "IStructureDetailsView.h" #include "IDetailPropertyRow.h" #include "DetailCategoryBuilder.h" #include "DetailWidgetRow.h" #include "Widgets/Layout/SSpacer.h" #include "Widgets/Input/SComboBox.h" #include "Widgets/Input/SButton.h" #include "Widgets/Input/SCheckBox.h" #include "PropertyEditorDelegates.h" #include "LevelInstance/LevelInstanceSubsystem.h" #include "Modules/ModuleManager.h" #include "GameFramework/Actor.h" #define LOCTEXT_NAMESPACE "LevelInstanceEditor" const FVector2D SNewLevelInstanceDialog::DEFAULT_WINDOW_SIZE = FVector2D(400, 250); void SNewLevelInstanceDialog::Construct(const FArguments& InArgs) { ParentWindowPtr = InArgs._ParentWindow.Get(); bClickedOk = false; FPropertyEditorModule& PropertyEditorModule = FModuleManager::GetModuleChecked("PropertyEditor"); TSharedPtr StructureDetailsView; FDetailsViewArgs DetailsViewArgs; { DetailsViewArgs.bAllowSearch = false; DetailsViewArgs.bHideSelectionTip = true; DetailsViewArgs.bLockable = false; DetailsViewArgs.bSearchInitialKeyFocus = true; DetailsViewArgs.bUpdatesFromSelection = false; DetailsViewArgs.NotifyHook = nullptr; DetailsViewArgs.bShowOptions = true; DetailsViewArgs.bShowModifiedPropertiesOption = false; DetailsViewArgs.bShowScrollBar = false; } FStructureDetailsViewArgs StructureViewArgs; { StructureViewArgs.bShowObjects = true; StructureViewArgs.bShowAssets = true; StructureViewArgs.bShowClasses = true; StructureViewArgs.bShowInterfaces = true; } StructureDetailsView = PropertyEditorModule.CreateStructureDetailView(DetailsViewArgs, StructureViewArgs, nullptr); StructureDetailsView->GetDetailsView()->SetGenericLayoutDetailsDelegate(FOnGetDetailCustomizationInstance::CreateStatic(&FNewLevelInstanceParamsDetails::MakeInstance, InArgs._PivotActors.Get())); FStructOnScope* Struct = new FStructOnScope(FNewLevelInstanceParams::StaticStruct(), (uint8*)&CreationParams); StructureDetailsView->SetStructureData(MakeShareable(Struct)); this->ChildSlot [ SNew(SBorder) .BorderImage(FAppStyle::GetBrush("ToolPanel.GroupBorder")) [ SNew(SVerticalBox) + SVerticalBox::Slot() .AutoHeight() [ SNew(SHorizontalBox) + SHorizontalBox::Slot() .AutoWidth() [ StructureDetailsView->GetWidget()->AsShared() ] ] + SVerticalBox::Slot() .AutoHeight() [ SNew(SHorizontalBox) + SHorizontalBox::Slot() .FillWidth(1.f) [ SNew(SSpacer) ] + SHorizontalBox::Slot() .AutoWidth() .Padding(2.f) [ SNew(SButton) .HAlign(HAlign_Center) .IsEnabled(this, &SNewLevelInstanceDialog::IsOkEnabled) .ContentPadding(FAppStyle::GetMargin("StandardDialog.ContentPadding")) .OnClicked(this, &SNewLevelInstanceDialog::OnOkClicked) .Text(LOCTEXT("OkButton", "Ok")) ] + SHorizontalBox::Slot() .AutoWidth() .Padding(2.f) [ SNew(SButton) .HAlign(HAlign_Center) .ContentPadding(FAppStyle::GetMargin("StandardDialog.ContentPadding")) .OnClicked(this, &SNewLevelInstanceDialog::OnCancelClicked) .Text(LOCTEXT("CancelButton", "Cancel")) ] ] + SVerticalBox::Slot() .AutoHeight() [ SNew(SHorizontalBox) + SHorizontalBox::Slot() .FillWidth(1.f) [ SNew(SCheckBox) .IsChecked_Lambda([this]() -> ECheckBoxState { return CreationParams.bAlwaysShowDialog ? ECheckBoxState::Checked : ECheckBoxState::Unchecked; }) .OnCheckStateChanged_Lambda([this](ECheckBoxState State) { CreationParams.bAlwaysShowDialog = State == ECheckBoxState::Checked; }) [ SNew(STextBlock) .Font(FCoreStyle::Get().GetFontStyle("SmallFont")) .Text(LOCTEXT("AlwaysShowDialog", "Always show dialog")) .ToolTipText(LOCTEXT("AlwaysShowDialogToolTip", "Show this dialog everytime a level instance is created. Can be changed in editor preferences (Content Editors > Level Instance).")) ] ] ] ] ]; } bool SNewLevelInstanceDialog::IsOkEnabled() const { if (CreationParams.PivotType == ELevelInstancePivotType::Actor && !CreationParams.PivotActor) { return false; } return true; } FReply SNewLevelInstanceDialog::OnOkClicked() { bClickedOk = true; ParentWindowPtr.Pin()->RequestDestroyWindow(); return FReply::Handled(); } FReply SNewLevelInstanceDialog::OnCancelClicked() { bClickedOk = false; ParentWindowPtr.Pin()->RequestDestroyWindow(); return FReply::Handled(); } TSharedRef FNewLevelInstanceParamsDetails::OnGeneratePivotActorWidget(AActor* Actor) const { // If a row wasn't generated just create the default one, a simple text block of the item's name. return SNew(STextBlock).Text(Actor ? FText::FromString(Actor->GetActorLabel()) : LOCTEXT("null", "null")).Font(IDetailLayoutBuilder::GetDetailFont()); } FText FNewLevelInstanceParamsDetails::GetSelectedPivotActorText() const { return CreationParams->PivotActor ? FText::FromString(CreationParams->PivotActor->GetActorLabel()) : LOCTEXT("none", "None"); } void FNewLevelInstanceParamsDetails::OnSelectedPivotActorChanged(AActor* NewValue, ESelectInfo::Type SelectionType) { CreationParams->PivotActor = NewValue; } bool FNewLevelInstanceParamsDetails::IsPivotActorSelectionEnabled() const { return CreationParams->PivotType == ELevelInstancePivotType::Actor; } void FNewLevelInstanceParamsDetails::CustomizeDetails(IDetailLayoutBuilder& DetailBuilder) { // Make sure we actually get a valid struct before continuing TArray> Structs; DetailBuilder.GetStructsBeingCustomized(Structs); if (Structs.Num() == 0) { // Nothing being customized return; } const UStruct* Struct = Structs[0]->GetStruct(); if (!Struct || Struct != FNewLevelInstanceParams::StaticStruct()) { // Invalid struct return; } // Get ptr to our actual type CreationParams = (FNewLevelInstanceParams*)Structs[0]->GetStructMemory(); TSharedPtr PivotTypeProperty = DetailBuilder.GetProperty(GET_MEMBER_NAME_CHECKED(FNewLevelInstanceParams, PivotType), (UClass*)FNewLevelInstanceParams::StaticStruct()); TSharedPtr PivotActorProperty = DetailBuilder.GetProperty(GET_MEMBER_NAME_CHECKED(FNewLevelInstanceParams, PivotActor), (UClass*)FNewLevelInstanceParams::StaticStruct()); IDetailCategoryBuilder& PivotCategoryBuilder = DetailBuilder.EditCategory("Pivot", FText::GetEmpty(), ECategoryPriority::Uncommon); PivotCategoryBuilder.AddProperty(PivotTypeProperty); IDetailPropertyRow& PivotActorPropertyRow = PivotCategoryBuilder.AddProperty(PivotActorProperty); TSharedPtr NameWidget; TSharedPtr ValueWidget; FDetailWidgetRow Row; PivotActorPropertyRow.GetDefaultWidgets(NameWidget, ValueWidget, Row); const bool bShowChildren = true; PivotActorPropertyRow.CustomWidget(bShowChildren) .NameContent() .MinDesiredWidth(Row.NameWidget.MinWidth) .MaxDesiredWidth(Row.NameWidget.MaxWidth) [ NameWidget.ToSharedRef() ] .ValueContent() .MinDesiredWidth(Row.ValueWidget.MinWidth) .MaxDesiredWidth(Row.ValueWidget.MaxWidth) [ SNew(SComboBox) .OptionsSource(&PivotActors) .OnGenerateWidget(this, &FNewLevelInstanceParamsDetails::OnGeneratePivotActorWidget) .OnSelectionChanged(this, &FNewLevelInstanceParamsDetails::OnSelectedPivotActorChanged) .IsEnabled(this, &FNewLevelInstanceParamsDetails::IsPivotActorSelectionEnabled) [ SNew(STextBlock) .Text(this, &FNewLevelInstanceParamsDetails::GetSelectedPivotActorText) .Font(DetailBuilder.GetDetailFont()) ] ]; } #undef LOCTEXT_NAMESPACE