// 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 DecoratedDisplayWidget; // The control widget for editing the value of the property in the specified config. TSharedPtr DisplayedValueWidget; EVisibility GetDisplayedValueWidgetVisibility() const; bool HandleDisplayedValueWidgetEnabled() const; // The capacity to add an entry to the specified config file TSharedPtr AddPropertyToConfigButton; FReply HandleAddPropertyToConfigClicked(); EVisibility GetAddPropertyToConfigButtonVisibility() const; // WIP.. The capacity to remove an entry from the specified config file TSharedPtr 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("ConfigEditor"); DisplayedValueWidget = ConfigEditorModule.GetValueWidgetForConfigProperty(PropertyOwnerDisplayObject->ConfigFileName); DisplayedValueWidget->SetEnabled(TAttribute::Create(TAttribute::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 OuterObjects; PropertyHandle->GetOuterObjects(OuterObjects); if (OuterObjects.Num() == 1) { UPropertyConfigFileDisplayRow* PropertyOwner = CastChecked(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