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

322 lines
9.0 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "PropertyVisualization/ConfigPropertyCellPresenter.h"
#include "ConfigPropertyHelper.h"
#include "Containers/Array.h"
#include "CoreGlobals.h"
#include "Delegates/Delegate.h"
#include "HAL/Platform.h"
#include "IConfigEditorModule.h"
#include "Input/Reply.h"
#include "Layout/Children.h"
#include "Layout/Margin.h"
#include "Layout/Visibility.h"
#include "Misc/Attribute.h"
#include "Misc/ConfigCacheIni.h"
#include "Modules/ModuleManager.h"
#include "PropertyHandle.h"
#include "SlotBase.h"
#include "Styling/AppStyle.h"
#include "Styling/CoreStyle.h"
#include "Styling/ISlateStyle.h"
#include "Styling/SlateColor.h"
#include "Templates/Casts.h"
#include "Types/SlateEnums.h"
#include "UObject/Class.h"
#include "UObject/FieldPath.h"
#include "UObject/NameTypes.h"
#include "UObject/UnrealType.h"
#include "Widgets/DeclarativeSyntaxSupport.h"
#include "Widgets/Images/SImage.h"
#include "Widgets/Input/SButton.h"
#include "Widgets/Layout/SBorder.h"
#include "Widgets/SBoxPanel.h"
#include "Widgets/SCompoundWidget.h"
#include "Widgets/SNullWidget.h"
#include "Widgets/SWidget.h"
class UObject;
struct FGeometry;
struct FPointerEvent;
#define LOCTEXT_NAMESPACE "ConfigEditor"
class SConfigPropertyCell
: public SCompoundWidget
{
public:
SLATE_USER_ARGS(SConfigPropertyCell) {}
SLATE_END_ARGS()
// Begin SCompoundWidget|SWidget interface
virtual void Construct(const FArguments& InArgs, UPropertyConfigFileDisplayRow* InPropertyOwnerDisplayObject);
virtual void OnMouseEnter(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override;
virtual void OnMouseLeave(const FPointerEvent& MouseEvent) override;
// End SCompoundWidget|SWidget interface
private:
// Create the displayable area for this cell.
void BuildDisplayAreaWidget();
// The shown display widget, includes all optional decoration
TSharedPtr<SWidget> DecoratedDisplayWidget;
// The control widget for editing the value of the property in the specified config.
TSharedPtr<SWidget> DisplayedValueWidget;
EVisibility GetDisplayedValueWidgetVisibility() const;
bool HandleDisplayedValueWidgetEnabled() const;
// The capacity to add an entry to the specified config file
TSharedPtr<SButton> AddPropertyToConfigButton;
FReply HandleAddPropertyToConfigClicked();
EVisibility GetAddPropertyToConfigButtonVisibility() const;
// WIP.. The capacity to remove an entry from the specified config file
TSharedPtr<SButton> RemovePropertyFromConfigButton;
FReply HandleRemovePropertyFromConfigClicked();
EVisibility GetRemovePropertyFromConfigVisibility() const;
// Check if the config file has an entry for this property
bool DoesConfigFileHaveEntryForProperty();
// Cached value of the above, as we use this for widget visibility callbacks.
bool bCachedConfigHasPropertyValue;
// The object which holds the property we are editing
UPropertyConfigFileDisplayRow* PropertyOwnerDisplayObject;
};
void SConfigPropertyCell::BuildDisplayAreaWidget()
{
IConfigEditorModule& ConfigEditorModule = FModuleManager::Get().GetModuleChecked<IConfigEditorModule>("ConfigEditor");
DisplayedValueWidget = ConfigEditorModule.GetValueWidgetForConfigProperty(PropertyOwnerDisplayObject->ConfigFileName);
DisplayedValueWidget->SetEnabled(TAttribute<bool>::Create(TAttribute<bool>::FGetter::CreateSP(this, &SConfigPropertyCell::HandleDisplayedValueWidgetEnabled)));
static const FName DefaultForegroundName("DefaultForeground");
SAssignNew(DecoratedDisplayWidget, SHorizontalBox)
// The widget to alter the objects value in a config file
+ SHorizontalBox::Slot()
[
SNew(SVerticalBox)
.Visibility(this, &SConfigPropertyCell::GetDisplayedValueWidgetVisibility)
+ SVerticalBox::Slot()
.AutoHeight()
.VAlign(EVerticalAlignment::VAlign_Center)
[
SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
.HAlign(HAlign_Center)
[
SNew(SBorder)
.BorderImage(FCoreStyle::Get().GetBrush("ToolPanel.GroupBorder"))
.ForegroundColor(FAppStyle::GetSlateColor(DefaultForegroundName))
.Padding(0.0f)
[
DisplayedValueWidget.ToSharedRef()
]
]
]
]
// The add to config widget
+ SHorizontalBox::Slot()
.HAlign(HAlign_Center)
[
SNew(SVerticalBox)
.Visibility(this, &SConfigPropertyCell::GetAddPropertyToConfigButtonVisibility)
+ SVerticalBox::Slot()
.AutoHeight()
.VAlign(EVerticalAlignment::VAlign_Center)
[
SAssignNew(AddPropertyToConfigButton, SButton)
.OnClicked(this, &SConfigPropertyCell::HandleAddPropertyToConfigClicked)
.ButtonStyle(FAppStyle::Get(), "HoverHintOnly")
[
SNew(SImage)
.Image(FAppStyle::GetBrush(TEXT("Plus")))
.ColorAndOpacity(FSlateColor::UseForeground())
]
]
]
// The remove from config widget
+ SHorizontalBox::Slot()
.AutoWidth()
.HAlign(HAlign_Center)
[
SNew(SVerticalBox)
.Visibility(this, &SConfigPropertyCell::GetRemovePropertyFromConfigVisibility)
+ SVerticalBox::Slot()
.AutoHeight()
.VAlign(EVerticalAlignment::VAlign_Center)
.Padding(FMargin(4.0f, 0.0f))
[
SAssignNew(RemovePropertyFromConfigButton, SButton)
.OnClicked(this, &SConfigPropertyCell::HandleRemovePropertyFromConfigClicked)
.ButtonStyle(FAppStyle::Get(), "HoverHintOnly")
[
SNew(SImage)
.Image(FAppStyle::GetBrush(TEXT("Cross")))
.ColorAndOpacity(FSlateColor::UseForeground())
]
]
];
}
void SConfigPropertyCell::Construct(const FArguments& InArgs, UPropertyConfigFileDisplayRow* InPropertyOwnerDisplayObject)
{
PropertyOwnerDisplayObject = InPropertyOwnerDisplayObject;
bCachedConfigHasPropertyValue = DoesConfigFileHaveEntryForProperty();
// Create the cell visualization
BuildDisplayAreaWidget();
ChildSlot
[
DecoratedDisplayWidget.ToSharedRef()
];
}
void SConfigPropertyCell::OnMouseEnter(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent)
{
}
void SConfigPropertyCell::OnMouseLeave(const FPointerEvent& MouseEvent)
{
}
EVisibility SConfigPropertyCell::GetDisplayedValueWidgetVisibility() const
{
return bCachedConfigHasPropertyValue ? EVisibility::Visible : EVisibility::Collapsed;
}
bool SConfigPropertyCell::HandleDisplayedValueWidgetEnabled() const
{
return PropertyOwnerDisplayObject->bIsFileWritable;
}
FReply SConfigPropertyCell::HandleAddPropertyToConfigClicked()
{
PropertyOwnerDisplayObject->TryUpdateDefaultConfigFile(PropertyOwnerDisplayObject->ConfigFileName);
bCachedConfigHasPropertyValue = true;
return FReply::Handled();
}
EVisibility SConfigPropertyCell::GetAddPropertyToConfigButtonVisibility() const
{
return (!bCachedConfigHasPropertyValue && PropertyOwnerDisplayObject->bIsFileWritable) ? EVisibility::Visible : EVisibility::Collapsed;
}
FReply SConfigPropertyCell::HandleRemovePropertyFromConfigClicked()
{
// This needs work...
UClass* OwnerClass = PropertyOwnerDisplayObject->ExternalProperty->GetOwnerClass();
FString SectionName = OwnerClass->GetPathName();
FString PropertyName = PropertyOwnerDisplayObject->ExternalProperty->GetName();
// This...
GConfig->RemoveKey(*SectionName, *PropertyName, PropertyOwnerDisplayObject->ConfigFileName);
// ... really oughta affect this...
PropertyOwnerDisplayObject->TryUpdateDefaultConfigFile(PropertyOwnerDisplayObject->ConfigFileName);
return FReply::Handled();
}
EVisibility SConfigPropertyCell::GetRemovePropertyFromConfigVisibility() const
{
/* Technical limitations of UObjects and Config make this difficult. Hopefully we can add it at some point. */
return EVisibility::Collapsed;
}
bool SConfigPropertyCell::DoesConfigFileHaveEntryForProperty()
{
UClass* OwnerClass = PropertyOwnerDisplayObject->ExternalProperty->GetOwnerClass();
FString SectionName = OwnerClass->GetPathName();
FString PropertyName = PropertyOwnerDisplayObject->ExternalProperty->GetName();
FString TempValue;
return GConfig->GetString(*SectionName, *PropertyName, TempValue, PropertyOwnerDisplayObject->ConfigFileName);
}
FConfigPropertyCellPresenter::FConfigPropertyCellPresenter(const TSharedPtr< IPropertyHandle > PropertyHandle)
{
TArray<UObject*> OuterObjects;
PropertyHandle->GetOuterObjects(OuterObjects);
if (OuterObjects.Num() == 1)
{
UPropertyConfigFileDisplayRow* PropertyOwner = CastChecked<UPropertyConfigFileDisplayRow>(OuterObjects[0]);
DisplayWidget = SNew(SConfigPropertyCell, PropertyOwner);
}
}
TSharedRef< class SWidget > FConfigPropertyCellPresenter::ConstructDisplayWidget()
{
return DisplayWidget.ToSharedRef();
}
bool FConfigPropertyCellPresenter::RequiresDropDown()
{
return false;
}
TSharedRef< class SWidget > FConfigPropertyCellPresenter::ConstructEditModeCellWidget()
{
return ConstructDisplayWidget();
}
TSharedRef< class SWidget > FConfigPropertyCellPresenter::ConstructEditModeDropDownWidget()
{
return SNullWidget::NullWidget;
}
TSharedRef< class SWidget > FConfigPropertyCellPresenter::WidgetToFocusOnEdit()
{
return SNullWidget::NullWidget;
}
bool FConfigPropertyCellPresenter::HasReadOnlyEditMode()
{
return true;
}
FString FConfigPropertyCellPresenter::GetValueAsString()
{
return FString();
}
FText FConfigPropertyCellPresenter::GetValueAsText()
{
return FText();
}
#undef LOCTEXT_NAMESPACE