Files
UnrealEngine/Engine/Source/Editor/AdvancedPreviewScene/Private/SAdvancedPreviewDetailsTab.cpp
2025-05-18 13:04:45 +08:00

347 lines
11 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "SAdvancedPreviewDetailsTab.h"
#include "Editor/EditorPerProjectUserSettings.h"
#include "Modules/ModuleManager.h"
#include "Widgets/SBoxPanel.h"
#include "Widgets/Text/STextBlock.h"
#include "Widgets/Input/SButton.h"
#include "Widgets/Input/STextComboBox.h"
#include "IDetailsView.h"
#include "PropertyEditorModule.h"
#include "ScopedTransaction.h"
#include "AssetViewerSettings.h"
#include "AdvancedPreviewScene.h"
#include "IDetailRootObjectCustomization.h"
#define LOCTEXT_NAMESPACE "SPrettyPreview"
SAdvancedPreviewDetailsTab::SAdvancedPreviewDetailsTab()
{
DefaultSettings = UAssetViewerSettings::Get();
if (DefaultSettings)
{
RefreshDelegate = DefaultSettings->OnAssetViewerSettingsChanged().AddRaw(this, &SAdvancedPreviewDetailsTab::OnAssetViewerSettingsRefresh);
AddRemoveProfileDelegate = DefaultSettings->OnAssetViewerProfileAddRemoved().AddLambda([this]() { this->Refresh(); });
PostUndoDelegate = DefaultSettings->OnAssetViewerSettingsPostUndo().AddRaw(this, &SAdvancedPreviewDetailsTab::OnAssetViewerSettingsPostUndo);
}
PerProjectSettings = GetMutableDefault<UEditorPerProjectUserSettings>();
}
SAdvancedPreviewDetailsTab::~SAdvancedPreviewDetailsTab()
{
DefaultSettings = UAssetViewerSettings::Get();
if (DefaultSettings)
{
DefaultSettings->OnAssetViewerSettingsChanged().Remove(RefreshDelegate);
DefaultSettings->OnAssetViewerProfileAddRemoved().Remove(AddRemoveProfileDelegate);
DefaultSettings->OnAssetViewerSettingsPostUndo().Remove(PostUndoDelegate);
DefaultSettings->Save();
}
}
void SAdvancedPreviewDetailsTab::Construct(const FArguments& InArgs, const TSharedRef<FAdvancedPreviewScene>& InPreviewScene)
{
PreviewScenePtr = InPreviewScene;
DefaultSettings = UAssetViewerSettings::Get();
AdditionalSettings = InArgs._AdditionalSettings;
ProfileIndex = PerProjectSettings->AssetViewerProfileIndex;
DetailCustomizations = InArgs._DetailCustomizations;
PropertyTypeCustomizations = InArgs._PropertyTypeCustomizations;
Delegates = InArgs._Delegates;
CreateSettingsView();
this->ChildSlot
[
SNew(SVerticalBox)
+ SVerticalBox::Slot()
.Padding(2.0f, 1.0f, 2.0f, 1.0f)
[
SNew(SHorizontalBox)
+SHorizontalBox::Slot()
[
SettingsView->AsShared()
]
]
+SVerticalBox::Slot()
.Padding(2.0f, 1.0f, 2.0f, 1.0f)
.AutoHeight()
[
SNew(SHorizontalBox)
+SHorizontalBox::Slot()
.Padding(2.0f)
[
SNew(SHorizontalBox)
.ToolTipText(LOCTEXT("SceneProfileComboBoxToolTip", "Allows for switching between scene environment and lighting profiles."))
+ SHorizontalBox::Slot()
.Padding(0.0f, 0.0f, 2.0f, 0.0f)
.AutoWidth()
.VAlign(VAlign_Center)
[
SNew(STextBlock)
.Text(LOCTEXT("SceneProfileSettingsLabel", "Profile"))
]
+ SHorizontalBox::Slot()
.VAlign(VAlign_Fill)
[
SAssignNew(ProfileComboBox, STextComboBox)
.OptionsSource(&ProfileNames)
.OnSelectionChanged(this, &SAdvancedPreviewDetailsTab::ComboBoxSelectionChanged)
.IsEnabled_Lambda([this]() -> bool
{
return ProfileNames.Num() > 1;
})
]
]
+ SHorizontalBox::Slot()
.Padding(2.0f)
.AutoWidth()
[
SNew(SButton)
.OnClicked(this, &SAdvancedPreviewDetailsTab::AddProfileButtonClick)
.Text(LOCTEXT("AddProfileButton", "Add Profile"))
.ToolTipText(LOCTEXT("SceneProfileAddProfile", "Adds a new profile."))
]
+ SHorizontalBox::Slot()
.Padding(2.0f)
.AutoWidth()
[
SNew(SButton)
.OnClicked(this, &SAdvancedPreviewDetailsTab::RemoveOrResetProfileButtonClick)
.Text_Lambda([this]()
{
if (DefaultSettings->Profiles[ProfileIndex].bIsEngineDefaultProfile)
{
return LOCTEXT("ResetProfileButton", "Reset Profile");
}
return LOCTEXT("RemoveProfileButton", "Remove Profile");
})
.ToolTipText_Lambda([this]()
{
if (DefaultSettings->Profiles[ProfileIndex].bIsEngineDefaultProfile)
{
return LOCTEXT("SceneProfileResetProfile", "Resets this engine profile to default settings. Cannot delete engine profiles.");
}
return LOCTEXT("SceneProfileRemoveProfile", "Removes the currently selected profile.");
})
.IsEnabled_Lambda([this]()->bool
{
return ProfileNames.Num() > 1;
})
]
]
];
UpdateProfileNames();
UpdateSettingsView();
}
void SAdvancedPreviewDetailsTab::ComboBoxSelectionChanged(TSharedPtr<FString> NewSelection, ESelectInfo::Type SelectInfo)
{
int32 NewSelectionIndex;
if (ProfileNames.Find(NewSelection, NewSelectionIndex))
{
ProfileIndex = NewSelectionIndex;
PerProjectSettings->AssetViewerProfileIndex = ProfileIndex;
UpdateSettingsView();
check(PreviewScenePtr.IsValid());
if (SelectInfo == ESelectInfo::Type::OnMouseClick)
{
PreviewScenePtr.Pin()->SetProfileIndex(ProfileIndex);
}
}
}
void SAdvancedPreviewDetailsTab::UpdateSettingsView()
{
TArray<UObject*> Objects;
if (AdditionalSettings)
{
Objects.Add(AdditionalSettings);
}
Objects.Add(DefaultSettings);
SettingsView->SetObjects(Objects, true);
}
void SAdvancedPreviewDetailsTab::UpdateProfileNames()
{
checkf(DefaultSettings->Profiles.Num(), TEXT("There should always be at least one profile available"));
ProfileNames.Empty();
for (FPreviewSceneProfile& Profile : DefaultSettings->Profiles)
{
FString Suffix = TEXT("");
if (Profile.bSharedProfile)
{
Suffix = TEXT(" (Shared)");
}
if (Profile.bIsEngineDefaultProfile)
{
Suffix = TEXT(" (Engine Default)");
}
ProfileNames.Add(TSharedPtr<FString>(new FString(Profile.ProfileName + Suffix)));
}
ProfileComboBox->RefreshOptions();
ProfileComboBox->SetSelectedItem(ProfileNames[ProfileIndex]);
}
FReply SAdvancedPreviewDetailsTab::AddProfileButtonClick()
{
const FScopedTransaction Transaction(LOCTEXT("AddSceneProfile", "Adding Preview Scene Profile"));
DefaultSettings->Modify();
// Add new profile to settings instance
ProfileIndex = DefaultSettings->Profiles.AddDefaulted();
FPreviewSceneProfile& NewProfile = DefaultSettings->Profiles.Last();
// Try to create a valid profile name when one is added
bool bFoundValidName = false;
int32 ProfileAppendNum = FMath::Max(0, DefaultSettings->Profiles.Num() - 1);
FString NewProfileName;
while (!bFoundValidName)
{
NewProfileName = FString::Printf(TEXT("Profile_%i"), ProfileAppendNum);
bool bValidName = true;
for (const FPreviewSceneProfile& Profile : DefaultSettings->Profiles)
{
if (Profile.ProfileName == NewProfileName)
{
bValidName = false;
break;
}
}
if (!bValidName)
{
++ProfileAppendNum;
}
bFoundValidName = bValidName;
}
NewProfile.ProfileName = NewProfileName;
PerProjectSettings->AssetViewerProfileIndex = ProfileIndex;
DefaultSettings->PostEditChange();
// Change selection to new profile so the user directly sees the profile that was added
Refresh();
ProfileComboBox->SetSelectedItem(ProfileNames.Last());
return FReply::Handled();
}
FReply SAdvancedPreviewDetailsTab::RemoveOrResetProfileButtonClick()
{
const FPreviewSceneProfile& CurrentProfile = DefaultSettings->Profiles[ProfileIndex];
if (CurrentProfile.bIsEngineDefaultProfile)
{
const FScopedTransaction Transaction(LOCTEXT("ResetSceneProfile", "Reset Preview Scene Profile"));
DefaultSettings->Modify();
const FPreviewSceneProfile* DefaultEditorProfile = GetMutableDefault<UDefaultEditorProfiles>()->GetProfile(CurrentProfile.ProfileName);
if (DefaultEditorProfile)
{
// Reset currently selected profile
DefaultSettings->Profiles[ProfileIndex] = *DefaultEditorProfile;
DefaultSettings->PostEditChange();
return FReply::Handled();
}
// if we get here, it means an engine-provided default profile was removed from the engine,
// in which case we should remove it...
}
const FScopedTransaction Transaction(LOCTEXT("RemoveSceneProfile", "Remove Preview Scene Profile"));
DefaultSettings->Modify();
// Remove currently selected profile
DefaultSettings->Profiles.RemoveAt(ProfileIndex);
ProfileIndex = DefaultSettings->Profiles.IsValidIndex(ProfileIndex - 1 ) ? ProfileIndex - 1 : 0;
PerProjectSettings->AssetViewerProfileIndex = ProfileIndex;
DefaultSettings->PostEditChange();
return FReply::Handled();
}
void SAdvancedPreviewDetailsTab::OnAssetViewerSettingsRefresh(const FName& InPropertyName)
{
if (!PreviewScenePtr.IsValid())
{
// this callback can fire when the editor is forcibly closed and tool modes revert the active profile
// when this happens, the preview scene is null even though this details tab hasn't been destroyed yet (and unregistered this delegate)
return;
}
if (InPropertyName == GET_MEMBER_NAME_CHECKED(FPreviewSceneProfile, ProfileName) || InPropertyName == GET_MEMBER_NAME_CHECKED(FPreviewSceneProfile, bSharedProfile))
{
Refresh();
}
}
void SAdvancedPreviewDetailsTab::CreateSettingsView()
{
// Create a property view
FPropertyEditorModule& EditModule = FModuleManager::Get().GetModuleChecked<FPropertyEditorModule>("PropertyEditor");
FDetailsViewArgs DetailsViewArgs;
DetailsViewArgs.NameAreaSettings = FDetailsViewArgs::HideNameArea;
DetailsViewArgs.bHideSelectionTip = true;
DetailsViewArgs.DefaultsOnlyVisibility = EEditDefaultsOnlyNodeVisibility::Automatic;
DetailsViewArgs.bShowOptions = false;
DetailsViewArgs.bAllowMultipleTopLevelObjects = true;
SettingsView = EditModule.CreateDetailView(DetailsViewArgs);
for (const FAdvancedPreviewSceneModule::FDetailCustomizationInfo& DetailCustomizationInfo : DetailCustomizations)
{
SettingsView->RegisterInstancedCustomPropertyLayout(DetailCustomizationInfo.Struct, DetailCustomizationInfo.OnGetDetailCustomizationInstance);
}
for (const FAdvancedPreviewSceneModule::FPropertyTypeCustomizationInfo& PropertyTypeCustomizationInfo : PropertyTypeCustomizations)
{
SettingsView->RegisterInstancedCustomPropertyTypeLayout(PropertyTypeCustomizationInfo.StructName, PropertyTypeCustomizationInfo.OnGetPropertyTypeCustomizationInstance);
}
for (FAdvancedPreviewSceneModule::FDetailDelegates& DetailDelegate : Delegates)
{
DetailDelegate.OnPreviewSceneChangedDelegate.AddSP(this, &SAdvancedPreviewDetailsTab::OnPreviewSceneChanged);
}
UpdateSettingsView();
}
void SAdvancedPreviewDetailsTab::Refresh()
{
PerProjectSettings->AssetViewerProfileIndex = DefaultSettings->Profiles.IsValidIndex(PerProjectSettings->AssetViewerProfileIndex) ? PerProjectSettings->AssetViewerProfileIndex : 0;
ProfileIndex = PerProjectSettings->AssetViewerProfileIndex;
UpdateProfileNames();
PreviewScenePtr.Pin()->SetProfileIndex(ProfileIndex);
UpdateSettingsView();
}
void SAdvancedPreviewDetailsTab::OnAssetViewerSettingsPostUndo()
{
Refresh();
PreviewScenePtr.Pin()->UpdateScene(DefaultSettings->Profiles[ProfileIndex]);
}
void SAdvancedPreviewDetailsTab::OnPreviewSceneChanged(TSharedRef<FAdvancedPreviewScene> PreviewScene)
{
PreviewScenePtr = PreviewScene;
Refresh();
}
#undef LOCTEXT_NAMESPACE