// Copyright 2019-Present LexLiu. All Rights Reserved. #include "DetailCustomization/UITextCustomization.h" #include "HAL/PlatformApplicationMisc.h" #include "Core/ActorComponent/UIText.h" #include "LGUIEditorModule.h" #include "DetailLayoutBuilder.h" #include "DetailCategoryBuilder.h" #include "IDetailGroup.h" #define LOCTEXT_NAMESPACE "UITextCustomization" FUITextCustomization::FUITextCustomization() { } FUITextCustomization::~FUITextCustomization() { } TSharedRef FUITextCustomization::MakeInstance() { return MakeShareable(new FUITextCustomization); } void FUITextCustomization::CustomizeDetails(IDetailLayoutBuilder& DetailBuilder) { TArray> targetObjects; DetailBuilder.GetObjectsBeingCustomized(targetObjects); TargetScriptPtr = Cast(targetObjects[0].Get()); if (TargetScriptPtr == nullptr) { UE_LOG(LGUIEditor, Log, TEXT("[UITextCustomization]Get TargetScript is null")); return; } IDetailCategoryBuilder& category = DetailBuilder.EditCategory("LGUI"); category.AddProperty(GET_MEMBER_NAME_CHECKED(UUIText, font)); category.AddProperty(GET_MEMBER_NAME_CHECKED(UUIText, text)); category.AddProperty(GET_MEMBER_NAME_CHECKED(UUIText, size)); category.AddProperty(GET_MEMBER_NAME_CHECKED(UUIText, space)); //text alignment { DetailBuilder.HideProperty(GET_MEMBER_NAME_CHECKED(UUIText, hAlign)); DetailBuilder.HideProperty(GET_MEMBER_NAME_CHECKED(UUIText, vAlign)); const FMargin OuterPadding(2, 0); const FMargin ContentPadding(2); auto hAlignPropertyHandle = DetailBuilder.GetProperty(GET_MEMBER_NAME_CHECKED(UUIText, hAlign)); auto vAlignPropertyHandle = DetailBuilder.GetProperty(GET_MEMBER_NAME_CHECKED(UUIText, vAlign)); category.AddCustomRow(LOCTEXT("Alignment", "Alignment")) .PropertyHandleList({ hAlignPropertyHandle, vAlignPropertyHandle }) .CopyAction(FUIAction( FExecuteAction::CreateSP(this, &FUITextCustomization::OnCopyAlignment) )) .PasteAction(FUIAction( FExecuteAction::CreateSP(this, &FUITextCustomization::OnPasteAlignment, hAlignPropertyHandle, vAlignPropertyHandle), FCanExecuteAction::CreateSP(this, &FUITextCustomization::OnCanPasteAlignment) )) .NameContent() [ SNew(STextBlock) .Text(LOCTEXT("Alignment", "Alignment")) .Font(IDetailLayoutBuilder::GetDetailFont()) ] .ValueContent() [ SNew(SHorizontalBox) +SHorizontalBox::Slot() .AutoWidth() [ SNew(SHorizontalBox) + SHorizontalBox::Slot() .AutoWidth() .Padding(OuterPadding) [ SNew( SCheckBox ) .Style(FAppStyle::Get(), "ToggleButtonCheckbox") .ToolTipText(LOCTEXT("AlignTextLeft", "Align Text Left")) .Padding(ContentPadding) .OnCheckStateChanged(this, &FUITextCustomization::HandleHorizontalAlignmentCheckStateChanged, hAlignPropertyHandle, EUITextParagraphHorizontalAlign::Left) .IsChecked(this, &FUITextCustomization::GetHorizontalAlignmentCheckState, hAlignPropertyHandle, EUITextParagraphHorizontalAlign::Left) [ SNew(SImage) .Image(FAppStyle::GetBrush("HorizontalAlignment_Left")) ] ] + SHorizontalBox::Slot() .AutoWidth() .Padding(OuterPadding) [ SNew(SCheckBox) .Style(FAppStyle::Get(), "ToggleButtonCheckbox") .ToolTipText(LOCTEXT("AlignTextCenter", "Align Text Center")) .Padding(ContentPadding) .OnCheckStateChanged(this, &FUITextCustomization::HandleHorizontalAlignmentCheckStateChanged, hAlignPropertyHandle, EUITextParagraphHorizontalAlign::Center) .IsChecked(this, &FUITextCustomization::GetHorizontalAlignmentCheckState, hAlignPropertyHandle, EUITextParagraphHorizontalAlign::Center) [ SNew(SImage) .Image(FAppStyle::GetBrush("HorizontalAlignment_Center")) ] ] + SHorizontalBox::Slot() .AutoWidth() .Padding(OuterPadding) [ SNew(SCheckBox) .Style(FAppStyle::Get(), "ToggleButtonCheckbox") .ToolTipText(LOCTEXT("AlignTextRight", "Align Text Right")) .Padding(ContentPadding) .OnCheckStateChanged(this, &FUITextCustomization::HandleHorizontalAlignmentCheckStateChanged, hAlignPropertyHandle, EUITextParagraphHorizontalAlign::Right) .IsChecked(this, &FUITextCustomization::GetHorizontalAlignmentCheckState, hAlignPropertyHandle, EUITextParagraphHorizontalAlign::Right) [ SNew(SImage) .Image(FAppStyle::GetBrush("HorizontalAlignment_Right")) ] ] ] +SHorizontalBox::Slot() .AutoWidth() .Padding(FMargin(2, 0)) [ SNew(SBox) .WidthOverride(1) [ SNew(SImage) .Image(FAppStyle::GetBrush("PropertyEditor.VerticalDottedLine")) .ColorAndOpacity(FLinearColor(1, 1, 1, 0.2f)) ] ] +SHorizontalBox::Slot() .AutoWidth() [ SNew(SHorizontalBox) + SHorizontalBox::Slot() .AutoWidth() .Padding(OuterPadding) [ SNew( SCheckBox ) .Style(FAppStyle::Get(), "ToggleButtonCheckbox") .ToolTipText(LOCTEXT("VAlignTop", "Vertically Align Top")) .Padding(ContentPadding) .OnCheckStateChanged(this, &FUITextCustomization::HandleVerticalAlignmentCheckStateChanged, vAlignPropertyHandle, EUITextParagraphVerticalAlign::Top) .IsChecked(this, &FUITextCustomization::GetVerticalAlignmentCheckState, vAlignPropertyHandle, EUITextParagraphVerticalAlign::Top) [ SNew(SImage) .Image(FAppStyle::GetBrush("VerticalAlignment_Top")) ] ] + SHorizontalBox::Slot() .AutoWidth() .Padding(OuterPadding) [ SNew(SCheckBox) .Style(FAppStyle::Get(), "ToggleButtonCheckbox") .ToolTipText(LOCTEXT("VAlignMiddle", "Vertically Align Middle")) .Padding(ContentPadding) .OnCheckStateChanged(this, &FUITextCustomization::HandleVerticalAlignmentCheckStateChanged, vAlignPropertyHandle, EUITextParagraphVerticalAlign::Middle) .IsChecked(this, &FUITextCustomization::GetVerticalAlignmentCheckState, vAlignPropertyHandle, EUITextParagraphVerticalAlign::Middle) [ SNew(SImage) .Image(FAppStyle::GetBrush("VerticalAlignment_Center")) ] ] + SHorizontalBox::Slot() .AutoWidth() .Padding(OuterPadding) [ SNew(SCheckBox) .Style(FAppStyle::Get(), "ToggleButtonCheckbox") .ToolTipText(LOCTEXT("VAlignBottom", "Vertically Align Bottom")) .Padding(ContentPadding) .OnCheckStateChanged(this, &FUITextCustomization::HandleVerticalAlignmentCheckStateChanged, vAlignPropertyHandle, EUITextParagraphVerticalAlign::Bottom) .IsChecked(this, &FUITextCustomization::GetVerticalAlignmentCheckState, vAlignPropertyHandle, EUITextParagraphVerticalAlign::Bottom) [ SNew(SImage) .Image(FAppStyle::GetBrush("VerticalAlignment_Bottom")) ] ] ] ] .OverrideResetToDefault(FResetToDefaultOverride::Create( TAttribute::CreateLambda([=] { return hAlignPropertyHandle->CanResetToDefault() || vAlignPropertyHandle->CanResetToDefault(); }), FSimpleDelegate::CreateLambda([=]() { hAlignPropertyHandle->ResetToDefault(); vAlignPropertyHandle->ResetToDefault(); }) )) ; } auto OverflowTypeHandle = DetailBuilder.GetProperty(GET_MEMBER_NAME_CHECKED(UUIText, overflowType)); OverflowTypeHandle->SetOnPropertyValueChanged(FSimpleDelegate::CreateSP(this, &FUITextCustomization::ForceRefresh, &DetailBuilder)); auto AdjustWidthHandle = DetailBuilder.GetProperty(GET_MEMBER_NAME_CHECKED(UUIText, adjustWidth)); AdjustWidthHandle->SetOnPropertyValueChanged(FSimpleDelegate::CreateSP(this, &FUITextCustomization::ForceRefresh, &DetailBuilder)); auto AdjustHeightHandle = DetailBuilder.GetProperty(GET_MEMBER_NAME_CHECKED(UUIText, adjustHeight)); AdjustHeightHandle->SetOnPropertyValueChanged(FSimpleDelegate::CreateSP(this, &FUITextCustomization::ForceRefresh, &DetailBuilder)); EUITextOverflowType OverflowType; OverflowTypeHandle->GetValue(*(uint8*)&OverflowType); TArray needToHidePropertyName; if (OverflowType == EUITextOverflowType::HorizontalOverflow) { needToHidePropertyName.Add(GET_MEMBER_NAME_CHECKED(UUIText, adjustHeight)); needToHidePropertyName.Add(GET_MEMBER_NAME_CHECKED(UUIText, adjustHeightRange)); needToHidePropertyName.Add(GET_MEMBER_NAME_CHECKED(UUIText, maxHorizontalWidth)); bool AdjustWidth; AdjustWidthHandle->GetValue(AdjustWidth); if (!AdjustWidth) { needToHidePropertyName.Add(GET_MEMBER_NAME_CHECKED(UUIText, adjustWidthRange)); } } else if (OverflowType == EUITextOverflowType::VerticalOverflow) { needToHidePropertyName.Add(GET_MEMBER_NAME_CHECKED(UUIText, adjustWidth)); needToHidePropertyName.Add(GET_MEMBER_NAME_CHECKED(UUIText, adjustWidthRange)); needToHidePropertyName.Add(GET_MEMBER_NAME_CHECKED(UUIText, maxHorizontalWidth)); bool AdjustHeight; AdjustHeightHandle->GetValue(AdjustHeight); if (!AdjustHeight) { needToHidePropertyName.Add(GET_MEMBER_NAME_CHECKED(UUIText, adjustHeightRange)); } } else if (OverflowType == EUITextOverflowType::HorizontalAndVerticalOverflow) { bool AdjustWidth; AdjustWidthHandle->GetValue(AdjustWidth); if (!AdjustWidth) { needToHidePropertyName.Add(GET_MEMBER_NAME_CHECKED(UUIText, adjustWidthRange)); } bool AdjustHeight; AdjustHeightHandle->GetValue(AdjustHeight); if (!AdjustHeight) { needToHidePropertyName.Add(GET_MEMBER_NAME_CHECKED(UUIText, adjustHeightRange)); } } else { needToHidePropertyName.Add(GET_MEMBER_NAME_CHECKED(UUIText, adjustHeight)); needToHidePropertyName.Add(GET_MEMBER_NAME_CHECKED(UUIText, adjustWidth)); needToHidePropertyName.Add(GET_MEMBER_NAME_CHECKED(UUIText, adjustHeightRange)); needToHidePropertyName.Add(GET_MEMBER_NAME_CHECKED(UUIText, adjustWidthRange)); needToHidePropertyName.Add(GET_MEMBER_NAME_CHECKED(UUIText, maxHorizontalWidth)); } auto RichTextHandle = DetailBuilder.GetProperty(GET_MEMBER_NAME_CHECKED(UUIText, richText)); RichTextHandle->SetOnPropertyValueChanged(FSimpleDelegate::CreateSP(this, &FUITextCustomization::ForceRefresh, &DetailBuilder)); bool richText = false; RichTextHandle->GetValue(richText); if (richText) { IDetailGroup& RichTextGroup = category.AddGroup(FName("RichText"), RichTextHandle->GetPropertyDisplayName()); RichTextGroup.HeaderProperty(RichTextHandle); RichTextGroup.AddPropertyRow(DetailBuilder.GetProperty(GET_MEMBER_NAME_CHECKED(UUIText, richTextTagFilterFlags))); RichTextGroup.AddPropertyRow(DetailBuilder.GetProperty(GET_MEMBER_NAME_CHECKED(UUIText, richTextCustomStyleData))); RichTextGroup.AddPropertyRow(DetailBuilder.GetProperty(GET_MEMBER_NAME_CHECKED(UUIText, richTextImageData))); RichTextGroup.AddPropertyRow(DetailBuilder.GetProperty(GET_MEMBER_NAME_CHECKED(UUIText, listRichTextImageObjectInOutliner))); RichTextGroup.AddPropertyRow(DetailBuilder.GetProperty(GET_MEMBER_NAME_CHECKED(UUIText, createdRichTextImageObjectArray))); } else { category.AddProperty(RichTextHandle); needToHidePropertyName.Add(GET_MEMBER_NAME_CHECKED(UUIText, richTextCustomStyleData)); needToHidePropertyName.Add(GET_MEMBER_NAME_CHECKED(UUIText, richTextImageData)); needToHidePropertyName.Add(GET_MEMBER_NAME_CHECKED(UUIText, listRichTextImageObjectInOutliner)); needToHidePropertyName.Add(GET_MEMBER_NAME_CHECKED(UUIText, createdRichTextImageObjectArray)); needToHidePropertyName.Add(GET_MEMBER_NAME_CHECKED(UUIText, richTextTagFilterFlags)); } for (auto item : needToHidePropertyName) { DetailBuilder.HideProperty(item); } auto fontHandle = DetailBuilder.GetProperty(GET_MEMBER_NAME_CHECKED(UUIText, font)); fontHandle->SetOnPropertyValueChanged(FSimpleDelegate::CreateLambda([=, this] { TargetScriptPtr->OnPostChangeFontProperty(); })); fontHandle->SetOnPropertyValuePreChange(FSimpleDelegate::CreateLambda([=, this]{ TargetScriptPtr->OnPreChangeFontProperty(); })); auto richTextImageDataHandle = DetailBuilder.GetProperty(GET_MEMBER_NAME_CHECKED(UUIText, richTextImageData)); richTextImageDataHandle->SetOnPropertyValueChanged(FSimpleDelegate::CreateLambda([=, this] { TargetScriptPtr->OnPostChangeRichTextImageDataProperty(); })); richTextImageDataHandle->SetOnPropertyValuePreChange(FSimpleDelegate::CreateLambda([=, this] { TargetScriptPtr->OnPreChangeRichTextImageDataProperty(); })); auto richTextCustomStyleDataHandle = DetailBuilder.GetProperty(GET_MEMBER_NAME_CHECKED(UUIText, richTextCustomStyleData)); richTextCustomStyleDataHandle->SetOnPropertyValueChanged(FSimpleDelegate::CreateLambda([=, this] { TargetScriptPtr->OnPostChangeRichTextCustomStyleDataProperty(); })); richTextCustomStyleDataHandle->SetOnPropertyValuePreChange(FSimpleDelegate::CreateLambda([=, this] { TargetScriptPtr->OnPreChangeRichTextCustomStyleDataProperty(); })); } void FUITextCustomization::ForceRefresh(IDetailLayoutBuilder* DetailBuilder) { if (auto Script = TargetScriptPtr.Get()) { DetailBuilder->ForceRefreshDetails(); } } void FUITextCustomization::HandleHorizontalAlignmentCheckStateChanged(ECheckBoxState InCheckboxState, TSharedRef PropertyHandle, EUITextParagraphHorizontalAlign ToAlignment) { PropertyHandle->SetValue((uint8)ToAlignment); } void FUITextCustomization::HandleVerticalAlignmentCheckStateChanged(ECheckBoxState InCheckboxState, TSharedRef PropertyHandle, EUITextParagraphVerticalAlign ToAlignment) { PropertyHandle->SetValue((uint8)ToAlignment); } ECheckBoxState FUITextCustomization::GetHorizontalAlignmentCheckState(TSharedRef PropertyHandle, EUITextParagraphHorizontalAlign ForAlignment) const { uint8 Value; if (PropertyHandle->GetValue(Value) == FPropertyAccess::Result::Success) { return Value == (uint8)ForAlignment ? ECheckBoxState::Checked : ECheckBoxState::Unchecked; } return ECheckBoxState::Unchecked; } ECheckBoxState FUITextCustomization::GetVerticalAlignmentCheckState(TSharedRef PropertyHandle, EUITextParagraphVerticalAlign ForAlignment) const { uint8 Value; if (PropertyHandle->GetValue(Value) == FPropertyAccess::Result::Success) { return Value == (uint8)ForAlignment ? ECheckBoxState::Checked : ECheckBoxState::Unchecked; } return ECheckBoxState::Unchecked; } #define BEGIN_ALIGNMENT_CLIPBOARD TEXT("Begin LGUI UIWidget") void FUITextCustomization::OnCopyAlignment() { if (TargetScriptPtr.IsValid()) { FString CopiedText = FString::Printf(TEXT("%s, hAlign=%d, vAlign=%d"), BEGIN_ALIGNMENT_CLIPBOARD, (int)TargetScriptPtr->hAlign, (int)TargetScriptPtr->vAlign); FPlatformApplicationMisc::ClipboardCopy(*CopiedText); } } void FUITextCustomization::OnPasteAlignment(TSharedRef HAlignPropertyHandle, TSharedRef VAlignPropertyHandle) { FString PastedText; FPlatformApplicationMisc::ClipboardPaste(PastedText); if (PastedText.StartsWith(BEGIN_ALIGNMENT_CLIPBOARD)) { uint8 tempUInt8; FParse::Value(*PastedText, TEXT("hAlign="), tempUInt8); HAlignPropertyHandle->SetValue(tempUInt8); FParse::Value(*PastedText, TEXT("vAlign="), tempUInt8); VAlignPropertyHandle->SetValue(tempUInt8); } } bool FUITextCustomization::OnCanPasteAlignment()const { FString PastedText; FPlatformApplicationMisc::ClipboardPaste(PastedText); return PastedText.StartsWith(BEGIN_ALIGNMENT_CLIPBOARD); } #undef LOCTEXT_NAMESPACE