// Copyright 2019-Present LexLiu. All Rights Reserved. #include "DetailCustomization/LGUIEventDelegateCustomization.h" #include "LGUIEditorStyle.h" #include "IDetailChildrenBuilder.h" #include "IDetailPropertyRow.h" #include "IDetailGroup.h" #include "IPropertyUtilities.h" #include "IPropertyTypeCustomization.h" #include "PropertyCustomizationHelpers.h" #include "LGUIEditorUtils.h" #include "Widget/LGUIVectorInputBox.h" #include "Widgets/Input/SRotatorInputBox.h" #include "Widgets/Colors/SColorBlock.h" #include "Widgets/Colors/SColorPicker.h" #include "Widgets/SWidget.h" #include "Math/UnitConversion.h" #include "STextPropertyEditableTextBox.h" #include "SEnumCombo.h" #include "Serialization/BufferArchive.h" #include "LGUIEditableTextPropertyHandle.h" #include "Widgets/Input/NumericUnitTypeInterface.inl" #define LOCTEXT_NAMESPACE "LGUIEventDelegateCustomization" UE_DISABLE_OPTIMIZATION #define LGUIEventActorSelfName "(ActorSelf)" TArray FLGUIEventDelegateCustomization::CopySourceData; TSharedPtr FLGUIEventDelegateCustomization::GetEventListHandle()const { return PropertyHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FLGUIEventDelegate, eventList))->AsArray(); } void FLGUIEventDelegateCustomization::CustomizeChildren(TSharedRef InPropertyHandle, IDetailChildrenBuilder& ChildBuilder, IPropertyTypeCustomizationUtils& CustomizationUtils) { PropertyUtilites = CustomizationUtils.GetPropertyUtilities(); PropertyHandle = InPropertyHandle; //add parameter type property bool bIsInWorld = false; TArray NodeSet; PropertyHandle->GetOuterObjects(NodeSet); if (NodeSet.Num() > 1) { auto TipText = LOCTEXT("NotSupportMultipleEdit_Content", "(Not support multiple edit)"); ChildBuilder.AddCustomRow(LOCTEXT("NotSupportMultipleEdit_Row", "NotSupportMultipleEdit")) .NameContent() [ SNew(STextBlock) .Text(this, &FLGUIEventDelegateCustomization::GetEventTitleName) .ToolTipText(PropertyHandle->GetToolTipText()) ] .ValueContent() [ SNew(STextBlock) .Text(TipText) .ToolTipText(TipText) .Font(IDetailLayoutBuilder::GetDetailFont()) .ColorAndOpacity(FLinearColor(FColor::Red)) .AutoWrapText(true) ] ; return; } auto OutObject = NodeSet[0]; bIsInWorld = OutObject->GetWorld() != nullptr; if (!bIsInWorld) { if (CanChangeParameterType) { AddNativeParameterTypeProperty(ChildBuilder); } return; } if (auto Component = Cast(OutObject)) { if (Component->GetOwner() && Component->GetOwner()->BlueprintCreatedComponents.Contains(Component)) { auto TipText = LOCTEXT("NotSupportActorBlueprintComponent_Content", "(Not support ActorBlueprint's component)"); ChildBuilder.AddCustomRow(LOCTEXT("NotSupportActorBlueprintComponent_Row", "NotSupportActorBlueprintComponent")) .NameContent() [ SNew(STextBlock) .Text(this, &FLGUIEventDelegateCustomization::GetEventTitleName) .ToolTipText(PropertyHandle->GetToolTipText()) ] .ValueContent() [ SNew(STextBlock) .Text(TipText) .ToolTipText(TipText) .Font(IDetailLayoutBuilder::GetDetailFont()) .ColorAndOpacity(FLinearColor(FColor::Red)) .AutoWrapText(true) ] ; return; } } // copy all EventDelegate I'm accessing right now TArray StructPtrs; PropertyHandle->AccessRawData(StructPtrs); check(StructPtrs.Num() != 0); EventDelegateInstances.AddZeroed(StructPtrs.Num()); for (auto Iter = StructPtrs.CreateIterator(); Iter; ++Iter) { check(*Iter); auto Item = (FLGUIEventDelegate*)(*Iter); EventDelegateInstances[Iter.GetIndex()] = Item; for (auto& listItem : Item->eventList) { listItem.CheckTargetObject(); } } auto EventListHandle = GetEventListHandle(); auto RefreshDelegate = FSimpleDelegate::CreateSP(this, &FLGUIEventDelegateCustomization::UpdateEventsLayout); EventListHandle->SetOnNumElementsChanged(RefreshDelegate); auto NativeParameterTypeHandle = PropertyHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FLGUIEventDelegate, supportParameterType)); NativeParameterTypeHandle->SetOnPropertyValueChanged(RefreshDelegate); auto EventParameterType = GetNativeParameterType(); ChildBuilder.AddCustomRow(LOCTEXT("EventDelegate", "EventDelegate")) .WholeRowContent() [ SNew(SBox) .Padding(FMargin(-10, 0, -2, 0)) [ SNew(SOverlay) + SOverlay::Slot() [ SNew(SBox) .HAlign(EHorizontalAlignment::HAlign_Center) .VAlign(EVerticalAlignment::VAlign_Center) [ SNew(SBox) .WidthOverride(1000) .HeightOverride(this, &FLGUIEventDelegateCustomization::GetEventTotalHeight) [ SNew(SImage) .Image(FLGUIEditorStyle::Get().GetBrush("LGUIEditor.EventGroup")) .ColorAndOpacity(FLinearColor(FColor(255, 255, 255, 255))) ] ] ] + SOverlay::Slot() [ SNew(SVerticalBox) + SVerticalBox::Slot() .AutoHeight() [ SNew(SBox) .Padding(FMargin(8, 0)) .HeightOverride(30) [ SNew(SHorizontalBox) +SHorizontalBox::Slot() .HAlign(EHorizontalAlignment::HAlign_Left) .VAlign(EVerticalAlignment::VAlign_Center) .AutoWidth() [ SNew(STextBlock) .Text(this, &FLGUIEventDelegateCustomization::GetEventTitleName) .ToolTipText(PropertyHandle->GetToolTipText()) //.Font(IDetailLayoutBuilder::GetDetailFont()) ] +SHorizontalBox::Slot() .HAlign(EHorizontalAlignment::HAlign_Right) [ IsParameterTypeValid(EventParameterType) ? ( SNew(SHorizontalBox) + SHorizontalBox::Slot() .AutoWidth() .HAlign(HAlign_Left) .VAlign(VAlign_Center) .Padding(2, 0) [ SNew(SHorizontalBox) + SHorizontalBox::Slot() [ PropertyCustomizationHelpers::MakeAddButton(FSimpleDelegate::CreateSP(this, &FLGUIEventDelegateCustomization::OnClickListAdd)) ] + SHorizontalBox::Slot() [ PropertyCustomizationHelpers::MakeEmptyButton(FSimpleDelegate::CreateSP(this, &FLGUIEventDelegateCustomization::OnClickListEmpty)) ] ] ) : ( SNew(SHorizontalBox) + SHorizontalBox::Slot() .HAlign(HAlign_Left) .VAlign(VAlign_Center) .Padding(2, 0) [ SNew(STextBlock) .AutoWrapText(true) .ColorAndOpacity(FSlateColor(FLinearColor::Red)) .Text(LOCTEXT("ParameterTypeWrong", "Parameter type is wrong!")) .Font(IDetailLayoutBuilder::GetDetailFont()) ] ) ] ] ] +SVerticalBox::Slot() [ SAssignNew(EventsWidget, SBox) ] ] ] ] ; UpdateEventsLayout(); } FText FLGUIEventDelegateCustomization::GetEventTitleName()const { auto EventParameterType = GetNativeParameterType(); auto NameStr = PropertyHandle->GetPropertyDisplayName().ToString(); FString ParamTypeString = ULGUIEventDelegateParameterHelper::ParameterTypeToName(EventParameterType, nullptr); NameStr = NameStr + "(" + ParamTypeString + ")"; return FText::FromString(NameStr); } FText FLGUIEventDelegateCustomization::GetEventItemFunctionName(TSharedRef EventItemPropertyHandle)const { //function auto FunctionNameHandle = EventItemPropertyHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FLGUIEventDelegateData, functionName)); FName FunctionFName; FunctionNameHandle->GetValue(FunctionFName); FString FunctionName = FunctionFName.ToString(); //parameterType auto FunctionParameterType = GetEventDataParameterType(EventItemPropertyHandle); bool ComponentValid = false;//event target component valid? bool EventFunctionValid = false;//event target function valid? UFunction* EventFunction = nullptr; if (auto TargetObject = GetEventItemTargetObject(EventItemPropertyHandle)) { EventFunction = TargetObject->FindFunction(FunctionFName); if (EventFunction) { if (ULGUIEventDelegateParameterHelper::IsStillSupported(EventFunction, FunctionParameterType)) { EventFunctionValid = true; } } } if (!EventFunctionValid)//function not valid, show tip { if (FunctionName != "None Function" && !FunctionName.IsEmpty()) { FString Prefix = "(NotValid)"; FunctionName = Prefix.Append(FunctionName); } } if (FunctionName.IsEmpty())FunctionName = "None Function"; return FText::FromString(FunctionName); } UObject* FLGUIEventDelegateCustomization::GetEventItemTargetObject(TSharedRef EventItemPropertyHandle)const { //TargetObject auto TargetObjectHandle = EventItemPropertyHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FLGUIEventDelegateData, TargetObject)); UObject* TargetObject = nullptr; TargetObjectHandle->GetValue(TargetObject); return TargetObject; } FText FLGUIEventDelegateCustomization::GetComponentDisplayName(TSharedRef EventItemPropertyHandle)const { FString ComponentDisplayName; auto TargetObject = GetEventItemTargetObject(EventItemPropertyHandle); auto HelperActor = GetEventItemHelperActor(EventItemPropertyHandle); if (TargetObject) { if (TargetObject == HelperActor) { ComponentDisplayName = LGUIEventActorSelfName; } else { if (auto Comp = Cast(TargetObject)) { ComponentDisplayName = TargetObject->GetName(); } else { ComponentDisplayName = "(WrongType)"; } } } else { ComponentDisplayName = "None"; } return FText::FromString(ComponentDisplayName); } EVisibility FLGUIEventDelegateCustomization::GetNativeParameterWidgetVisibility(TSharedRef EventItemPropertyHandle)const { auto TargetObject = GetEventItemTargetObject(EventItemPropertyHandle); //function auto FunctionNameHandle = EventItemPropertyHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FLGUIEventDelegateData, functionName)); FName FunctionFName; FunctionNameHandle->GetValue(FunctionFName); //parameterType auto FunctionParameterType = GetEventDataParameterType(EventItemPropertyHandle); UFunction* EventFunction = nullptr; auto EventParameterType = GetNativeParameterType(); if (TargetObject) { EventFunction = TargetObject->FindFunction(FunctionFName); } if (IsValid(TargetObject) && IsValid(EventFunction)) { bool bUseNativeParameter = false; auto UseNativeParameterHandle = EventItemPropertyHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FLGUIEventDelegateData, UseNativeParameter)); UseNativeParameterHandle->GetValue(bUseNativeParameter); if ((EventParameterType == FunctionParameterType) && bUseNativeParameter)//support native parameter { return EVisibility::Visible; } } return EVisibility::Collapsed; } EVisibility FLGUIEventDelegateCustomization::GetDrawFunctionParameterWidgetVisibility(TSharedRef EventItemPropertyHandle)const { auto TargetObject = GetEventItemTargetObject(EventItemPropertyHandle); //function auto FunctionNameHandle = EventItemPropertyHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FLGUIEventDelegateData, functionName)); FName FunctionFName; FunctionNameHandle->GetValue(FunctionFName); //parameterType auto FunctionParameterType = GetEventDataParameterType(EventItemPropertyHandle); UFunction* EventFunction = nullptr; auto EventParameterType = GetNativeParameterType(); if (TargetObject) { EventFunction = TargetObject->FindFunction(FunctionFName); } if (IsValid(TargetObject) && IsValid(EventFunction)) { bool bUseNativeParameter = false; auto UseNativeParameterHandle = EventItemPropertyHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FLGUIEventDelegateData, UseNativeParameter)); UseNativeParameterHandle->GetValue(bUseNativeParameter); if ((EventParameterType == FunctionParameterType) && bUseNativeParameter)//support native parameter { } else { return EVisibility::Visible; } } return EVisibility::Collapsed; } EVisibility FLGUIEventDelegateCustomization::GetNotValidParameterWidgetVisibility(TSharedRef EventItemPropertyHandle)const { auto TargetObject = GetEventItemTargetObject(EventItemPropertyHandle); //function auto FunctionNameHandle = EventItemPropertyHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FLGUIEventDelegateData, functionName)); FName FunctionFName; FunctionNameHandle->GetValue(FunctionFName); //parameterType auto FunctionParameterType = GetEventDataParameterType(EventItemPropertyHandle); UFunction* EventFunction = nullptr; auto EventParameterType = GetNativeParameterType(); if (TargetObject) { EventFunction = TargetObject->FindFunction(FunctionFName); } if (IsValid(TargetObject) && IsValid(EventFunction)) { return EVisibility::Collapsed; } else { return EVisibility::Visible; } } AActor* FLGUIEventDelegateCustomization::GetEventItemHelperActor(TSharedRef EventItemPropertyHandle)const { //HelperActor auto HelperActorHandle = EventItemPropertyHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FLGUIEventDelegateData, HelperActor)); AActor* HelperActor = nullptr; UObject* HelperActorObject = nullptr; HelperActorHandle->GetValue(HelperActorObject); if (HelperActorObject != nullptr) { HelperActor = Cast(HelperActorObject); } return HelperActor; } void FLGUIEventDelegateCustomization::UpdateEventsLayout() { auto EventParameterType = GetNativeParameterType(); auto EventListHandle = GetEventListHandle(); auto EventsVerticalLayout = SNew(SVerticalBox); EventParameterWidgetArray.Empty(); uint32 arrayCount; EventListHandle->GetNumElements(arrayCount); for (int32 EventItemIndex = 0; EventItemIndex < (int32)arrayCount; EventItemIndex++) { auto ItemPropertyHandle = EventListHandle->GetElement(EventItemIndex); //HelperActor auto HelperActorHandle = ItemPropertyHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FLGUIEventDelegateData, HelperActor)); UObject* HelperActorObject = nullptr; HelperActorHandle->GetValue(HelperActorObject); AActor* HelperActor = Cast(HelperActorObject); //TargetObject auto TargetObjectHandle = ItemPropertyHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FLGUIEventDelegateData, TargetObject)); UObject* TargetObject = nullptr; TargetObjectHandle->GetValue(TargetObject); UObject* ClassObject = nullptr; auto HelperClassHandle = ItemPropertyHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FLGUIEventDelegateData, HelperClass)); HelperClassHandle->GetValue(ClassObject); if (ClassObject != nullptr) { UClass* ClassValue = Cast(ClassObject); if (ClassValue == AActor::StaticClass()) { TargetObjectHandle->SetValue(HelperActor); } else if (ClassValue->IsChildOf(UActorComponent::StaticClass())) { if (HelperActor != nullptr) { UActorComponent* FoundHelperComp = nullptr; TArray CompArray; HelperActor->GetComponents(ClassValue, CompArray); if (CompArray.Num() == 1) { FoundHelperComp = CompArray[0]; } else if (CompArray.Num() > 1) { FName HelperComponentName = NAME_None; auto HelperComponentNameHandle = ItemPropertyHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FLGUIEventDelegateData, HelperComponentName)); HelperComponentNameHandle->GetValue(HelperComponentName); if (!HelperComponentName.IsNone()) { for (auto& Comp : CompArray) { if (Comp->GetFName() == HelperComponentName) { FoundHelperComp = Comp; break; } } } } if (FoundHelperComp != TargetObject) { TargetObjectHandle->SetValue(FoundHelperComp); } } else { if (TargetObject != nullptr) { TargetObjectHandle->SetValue((UObject*)nullptr); } } } } else { if (TargetObject != nullptr) { TargetObjectHandle->SetValue((UObject*)nullptr); } } HelperActorHandle->SetOnPropertyValueChanged(FSimpleDelegate::CreateSP(this, &FLGUIEventDelegateCustomization::OnActorParameterChange, ItemPropertyHandle)); //function auto FunctionNameHandle = ItemPropertyHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FLGUIEventDelegateData, functionName)); FName FunctionFName; FunctionNameHandle->GetValue(FunctionFName); //parameterType auto paramTypeHandle = ItemPropertyHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FLGUIEventDelegateData, ParamType)); paramTypeHandle->SetOnPropertyValueChanged(FSimpleDelegate::CreateSP(this, &FLGUIEventDelegateCustomization::OnParameterTypeChange, ItemPropertyHandle)); auto FunctionParameterType = GetEventDataParameterType(ItemPropertyHandle); UFunction* EventFunction = nullptr; if (TargetObject) { EventFunction = TargetObject->FindFunction(FunctionFName); } TSharedRef ParameterWidget = SNew(SBox); if (IsValid(TargetObject) && IsValid(EventFunction)) { bool bUseNativeParameter = false; auto UseNativeParameterHandle = ItemPropertyHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FLGUIEventDelegateData, UseNativeParameter)); UseNativeParameterHandle->GetValue(bUseNativeParameter); if (EventParameterType != FunctionParameterType)//check "bUseNativeParameter" parameter { if (bUseNativeParameter) { bUseNativeParameter = false; UseNativeParameterHandle->SetValue(bUseNativeParameter); } } if ((EventParameterType == FunctionParameterType) && bUseNativeParameter)//support native parameter { //clear buffer and value ClearValueBuffer(ItemPropertyHandle); ClearReferenceValue(ItemPropertyHandle); //native parameter AnchorData ParameterWidget = SNew(SBox) .VAlign(EVerticalAlignment::VAlign_Center) [ SNew(STextBlock) .Text(LOCTEXT("(NativeParameter)", "(NativeParameter)")) .Font(IDetailLayoutBuilder::GetDetailFont()) ] ; } else { ParameterWidget = DrawFunctionParameter(ItemPropertyHandle, FunctionParameterType, EventFunction); } } else { ParameterWidget = SNew(SBox) .VAlign(EVerticalAlignment::VAlign_Center) [ SNew(STextBlock) .Text(LOCTEXT("(NotValid)", "(NotValid)")) .Font(IDetailLayoutBuilder::GetDetailFont()) ] ; } ParameterWidget->SetToolTipText(LOCTEXT("Parameter", "Set parameter for the function of this event")); EventParameterWidgetArray.Add(ParameterWidget); //additional button int additionalButtonHeight = 20; auto additionalButtons = SNew(SBox) [ //copy, paste, add, delete SNew(SHorizontalBox) + SHorizontalBox::Slot() .HAlign(HAlign_Right) [ SNew(SHorizontalBox) + SHorizontalBox::Slot() .AutoWidth() [ SNew(SVerticalBox) +SVerticalBox::Slot() .AutoHeight() [ SNew(SBox) .HeightOverride(additionalButtonHeight) [ SNew(SButton) .HAlign(HAlign_Center) .VAlign(VAlign_Center) .Text(LOCTEXT("C", "C")) .OnClicked(this, &FLGUIEventDelegateCustomization::OnClickCopyPaste, true, EventItemIndex) .ToolTipText(LOCTEXT("Copy", "Copy this function")) ] ] ] + SHorizontalBox::Slot() .AutoWidth() [ SNew(SVerticalBox) + SVerticalBox::Slot() .AutoHeight() [ SNew(SBox) .HeightOverride(additionalButtonHeight) [ SNew(SButton) .HAlign(HAlign_Center) .VAlign(VAlign_Center) .Text(LOCTEXT("P", "P")) .OnClicked(this, &FLGUIEventDelegateCustomization::OnClickCopyPaste, false, EventItemIndex) .ToolTipText(LOCTEXT("Paste", "Paste copied function to this function")) ] ] ] + SHorizontalBox::Slot() .AutoWidth() [ SNew(SVerticalBox) + SVerticalBox::Slot() .AutoHeight() [ SNew(SBox) .HeightOverride(additionalButtonHeight) [ SNew(SButton) .HAlign(HAlign_Center) .VAlign(VAlign_Center) .Text(LOCTEXT("D", "D")) .OnClicked(this, &FLGUIEventDelegateCustomization::OnClickDuplicate, EventItemIndex) .ToolTipText(LOCTEXT("Duplicate", "Duplicate this function")) ] ] ] + SHorizontalBox::Slot() .AutoWidth() [ SNew(SVerticalBox) + SVerticalBox::Slot() .AutoHeight() [ SNew(SBox) .HeightOverride(additionalButtonHeight) [ SNew(SButton) .HAlign(HAlign_Center) .VAlign(VAlign_Center) .Text(LOCTEXT("+", "+")) .OnClicked(this, &FLGUIEventDelegateCustomization::OnClickAddRemove, true, EventItemIndex, (int32)arrayCount) .ToolTipText(LOCTEXT("Add", "Add new one")) ] ] ] + SHorizontalBox::Slot() .AutoWidth() [ SNew(SVerticalBox) + SVerticalBox::Slot() .AutoHeight() [ SNew(SBox) .HeightOverride(additionalButtonHeight) [ SNew(SButton) .HAlign(HAlign_Center) .VAlign(VAlign_Center) .Text(LOCTEXT("-", "-")) .OnClicked(this, &FLGUIEventDelegateCustomization::OnClickAddRemove, false, EventItemIndex, (int32)arrayCount) .ToolTipText(LOCTEXT("Delete", "Delete this one")) ] ] ] + SHorizontalBox::Slot() .AutoWidth() [ SNew(SVerticalBox) + SVerticalBox::Slot() .AutoHeight() [ SNew(SBox) .HeightOverride(additionalButtonHeight) [ SNew(SButton) .HAlign(HAlign_Center) .VAlign(VAlign_Center) .Text(LOCTEXT("▲", "▲")) .OnClicked(this, &FLGUIEventDelegateCustomization::OnClickMoveUpDown, true, EventItemIndex) .ToolTipText(LOCTEXT("MoveUp", "Move up")) ] ] ] + SHorizontalBox::Slot() .AutoWidth() [ SNew(SVerticalBox) + SVerticalBox::Slot() .AutoHeight() [ SNew(SBox) .HeightOverride(additionalButtonHeight) [ SNew(SButton) .HAlign(HAlign_Center) .VAlign(VAlign_Center) .Text(LOCTEXT("▼", "▼")) .OnClicked(this, &FLGUIEventDelegateCustomization::OnClickMoveUpDown, false, EventItemIndex) .ToolTipText(LOCTEXT("MoveDown", "Move down")) ] ] ] ] ]; EventsVerticalLayout->AddSlot() .AutoHeight() [ SNew(SBox) .Padding(FMargin(2, 0)) [ SNew(SOverlay) + SOverlay::Slot() [ SNew(SVerticalBox) +SVerticalBox::Slot() .AutoHeight() .HAlign(EHorizontalAlignment::HAlign_Center) .VAlign(EVerticalAlignment::VAlign_Center) [ SNew(SBox) .WidthOverride(1000) .HeightOverride(this, &FLGUIEventDelegateCustomization::GetEventItemHeight, EventItemIndex) [ SNew(SImage) .Image(FLGUIEditorStyle::Get().GetBrush("LGUIEditor.EventItem")) .ColorAndOpacity(FLinearColor(FColor(255, 255, 255, 255))) ] ] ] + SOverlay::Slot() [ SNew(SBox) .Padding(FMargin(4, 4)) [ SNew(SVerticalBox) +SVerticalBox::Slot() .AutoHeight() [ SNew(SBox) .Padding(FMargin(0, 0, 0, 2)) [ SNew(SHorizontalBox) +SHorizontalBox::Slot() [ //HelperActor SNew(SBox) .Padding(FMargin(0, 0, 6, 0)) [ HelperActorHandle->CreatePropertyValueWidget() ] ] +SHorizontalBox::Slot() [ SNew(SBox) .HeightOverride(26) [ //Component SNew(SComboButton) .HasDownArrow(true) .IsEnabled(this, &FLGUIEventDelegateCustomization::IsComponentSelectorMenuEnabled, ItemPropertyHandle) .ToolTipText(LOCTEXT("Component", "Pick component for this event")) .ButtonContent() [ SNew(STextBlock) .Text(this, &FLGUIEventDelegateCustomization::GetComponentDisplayName, ItemPropertyHandle) .Font(IDetailLayoutBuilder::GetDetailFont()) ] .MenuContent() [ MakeComponentSelectorMenu(EventItemIndex) ] ] ] ] ] +SVerticalBox::Slot() .AutoHeight() [ SNew(SBox) .Padding(FMargin(0, 0, 0, 2)) [ SNew(SHorizontalBox) +SHorizontalBox::Slot() [ SNew(SBox) .Padding(FMargin(0, 0, 6, 0)) [ SNew(SBox) .HeightOverride(26) [ //function SNew(SComboButton) .HasDownArrow(true) .IsEnabled(this, &FLGUIEventDelegateCustomization::IsFunctionSelectorMenuEnabled, ItemPropertyHandle) .ToolTipText(LOCTEXT("Function", "Pick a function to execute of this event")) .ButtonContent() [ SNew(STextBlock) .Text(this, &FLGUIEventDelegateCustomization::GetEventItemFunctionName, ItemPropertyHandle) .Font(IDetailLayoutBuilder::GetDetailFont()) ] .MenuContent() [ MakeFunctionSelectorMenu(EventItemIndex) ] ] ] ] +SHorizontalBox::Slot() [ //parameter ParameterWidget ] ] ] +SVerticalBox::Slot() [ additionalButtons ] ] ] ] ] ; } EventsWidget->SetContent(EventsVerticalLayout); } void FLGUIEventDelegateCustomization::OnActorParameterChange(TSharedRef ItemPropertyHandle) { UObject* HelperActorObject = nullptr; auto HelperActorHandle = ItemPropertyHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FLGUIEventDelegateData, HelperActor)); HelperActorHandle->GetValue(HelperActorObject); AActor* HelperActor = Cast(HelperActorObject); auto TargetObjectHandle = ItemPropertyHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FLGUIEventDelegateData, TargetObject)); UObject* TargetObject = nullptr; TargetObjectHandle->GetValue(TargetObject); UObject* ClassObject = nullptr; auto HelperClassHandle = ItemPropertyHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FLGUIEventDelegateData, HelperClass)); HelperClassHandle->GetValue(ClassObject); if (ClassObject != nullptr) { UClass* ClassValue = Cast(ClassObject); if (ClassValue == AActor::StaticClass()) { TargetObjectHandle->SetValue(HelperActor); } else if (ClassValue->IsChildOf(UActorComponent::StaticClass())) { if (HelperActor != nullptr) { UActorComponent* FoundHelperComp = nullptr; TArray CompArray; HelperActor->GetComponents(ClassValue, CompArray); if (CompArray.Num() == 1) { FoundHelperComp = CompArray[0]; } else if (CompArray.Num() > 1) { FName HelperComponentName = NAME_None; auto HelperComponentNameHandle = ItemPropertyHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FLGUIEventDelegateData, HelperComponentName)); HelperComponentNameHandle->GetValue(HelperComponentName); if (!HelperComponentName.IsNone()) { for (auto& Comp : CompArray) { if (Comp->GetFName() == HelperComponentName) { FoundHelperComp = Comp; break; } } } } if (FoundHelperComp != TargetObject) { TargetObjectHandle->SetValue(FoundHelperComp); } } else { if (TargetObject != nullptr) { TargetObjectHandle->SetValue((UObject*)nullptr); } } } } else { if (TargetObject != nullptr) { TargetObjectHandle->SetValue((UObject*)nullptr); } } UpdateEventsLayout(); } void FLGUIEventDelegateCustomization::OnSelectComponent(UActorComponent* Comp, TSharedRef ItemPropertyHandle) { auto TargetObjectHandle = ItemPropertyHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FLGUIEventDelegateData, TargetObject)); TargetObjectHandle->SetValue(Comp); auto HelperClassHandle = ItemPropertyHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FLGUIEventDelegateData, HelperClass)); HelperClassHandle->SetValue(Comp->GetClass()); auto HelperComponentNameHandle = ItemPropertyHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FLGUIEventDelegateData, HelperComponentName)); HelperComponentNameHandle->SetValue(Comp->GetFName()); UpdateEventsLayout(); } void FLGUIEventDelegateCustomization::OnSelectActorSelf(TSharedRef ItemPropertyHandle) { auto HelperActorHandle = ItemPropertyHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FLGUIEventDelegateData, HelperActor)); UObject* HelperActorObject = nullptr; HelperActorHandle->GetValue(HelperActorObject); auto TargetObjectHandle = ItemPropertyHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FLGUIEventDelegateData, TargetObject)); TargetObjectHandle->SetValue(HelperActorObject); auto HelperClassHandle = ItemPropertyHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FLGUIEventDelegateData, HelperClass)); HelperClassHandle->SetValue(AActor::StaticClass()); auto HelperComponentNameHandle = ItemPropertyHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FLGUIEventDelegateData, HelperComponentName)); HelperComponentNameHandle->SetValue(NAME_None); UpdateEventsLayout(); } void FLGUIEventDelegateCustomization::OnSelectFunction(FName FuncName, ELGUIEventDelegateParameterType ParamType, bool UseNativeParameter, TSharedRef ItemPropertyHandle) { auto nameHandle = ItemPropertyHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FLGUIEventDelegateData, functionName)); nameHandle->SetValue(FuncName); SetEventDataParameterType(ItemPropertyHandle, ParamType); auto UseNativeParameterHandle = ItemPropertyHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FLGUIEventDelegateData, UseNativeParameter)); UseNativeParameterHandle->SetValue(UseNativeParameter); UpdateEventsLayout(); } void FLGUIEventDelegateCustomization::SetEventDataParameterType(TSharedRef EventDataItemHandle, ELGUIEventDelegateParameterType ParameterType) { auto ParamTypeHandle = EventDataItemHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FLGUIEventDelegateData, ParamType)); ParamTypeHandle->SetValue((uint8)ParameterType); } ELGUIEventDelegateParameterType FLGUIEventDelegateCustomization::GetNativeParameterType()const { auto NativeParameterTypeHandle = PropertyHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FLGUIEventDelegate, supportParameterType)); uint8 supportParameterTypeUint8; NativeParameterTypeHandle->GetValue(supportParameterTypeUint8); ELGUIEventDelegateParameterType eventParameterType = (ELGUIEventDelegateParameterType)supportParameterTypeUint8; return eventParameterType; } void FLGUIEventDelegateCustomization::AddNativeParameterTypeProperty(IDetailChildrenBuilder& ChildBuilder) { auto NativeParameterTypeHandle = PropertyHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FLGUIEventDelegate, supportParameterType)); ChildBuilder.AddProperty(NativeParameterTypeHandle.ToSharedRef()); } ELGUIEventDelegateParameterType FLGUIEventDelegateCustomization::GetEventDataParameterType(TSharedRef EventDataItemHandle)const { auto paramTypeHandle = EventDataItemHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FLGUIEventDelegateData, ParamType)); uint8 functionParameterTypeUint8; paramTypeHandle->GetValue(functionParameterTypeUint8); ELGUIEventDelegateParameterType functionParameterType = (ELGUIEventDelegateParameterType)functionParameterTypeUint8; return functionParameterType; } TSharedRef FLGUIEventDelegateCustomization::MakeComponentSelectorMenu(int32 itemIndex) { auto EventListHandle = GetEventListHandle(); auto ItemPropertyHandle = EventListHandle->GetElement(itemIndex); auto HelperActorHandle = ItemPropertyHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FLGUIEventDelegateData, HelperActor)); UObject* HelperActorObject = nullptr; HelperActorHandle->GetValue(HelperActorObject); if (HelperActorObject == nullptr) { return SNew(SBox); } FMenuBuilder MenuBuilder(true, MakeShareable(new FUICommandList)); auto HelperActor = (AActor*)HelperActorObject; MenuBuilder.AddMenuEntry( FUIAction(FExecuteAction::CreateRaw(this, &FLGUIEventDelegateCustomization::OnSelectActorSelf, ItemPropertyHandle)), SNew(SHorizontalBox) + SHorizontalBox::Slot() [ SNew(STextBlock) .Text(FText::FromString(LGUIEventActorSelfName)) .Font(IDetailLayoutBuilder::GetDetailFont()) ] //+SHorizontalBox::Slot() //.HAlign(EHorizontalAlignment::HAlign_Right) //[ // SNew(STextBlock) // .Text(FText::FromString(HelperActor->GetClass()->GetName())) // .Font(IDetailLayoutBuilder::GetDetailFont()) //] ); auto Components = HelperActor->GetComponents(); for (auto Comp : Components) { if(Comp->HasAnyFlags(EObjectFlags::RF_Transient))continue; auto CompName = Comp->GetFName(); auto CompTypeName = Comp->GetClass()->GetName(); MenuBuilder.AddMenuEntry( FUIAction(FExecuteAction::CreateRaw(this, &FLGUIEventDelegateCustomization::OnSelectComponent, Comp, ItemPropertyHandle)), SNew(SHorizontalBox) + SHorizontalBox::Slot() .HAlign(EHorizontalAlignment::HAlign_Left) [ SNew(STextBlock) .Text(FText::FromString(CompName.ToString())) .Font(IDetailLayoutBuilder::GetDetailFont()) ] //+ SHorizontalBox::Slot() //.HAlign(EHorizontalAlignment::HAlign_Right) //[ // SNew(STextBlock) // .Text(FText::FromString(CompTypeName)) // .Font(IDetailLayoutBuilder::GetDetailFont()) //] ); } return MenuBuilder.MakeWidget(); } TSharedRef FLGUIEventDelegateCustomization::MakeFunctionSelectorMenu(int32 itemIndex) { auto EventListHandle = GetEventListHandle(); auto EventParameterType = GetNativeParameterType(); auto ItemPropertyHandle = EventListHandle->GetElement(itemIndex); auto TargetObjectHandle = ItemPropertyHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FLGUIEventDelegateData, TargetObject)); UObject* TargetObject = nullptr; TargetObjectHandle->GetValue(TargetObject); if (TargetObject == nullptr) { return SNew(SBox); } FMenuBuilder MenuBuilder(true, MakeShareable(new FUICommandList)); auto FunctionField = TFieldRange(TargetObject->GetClass()); for (auto Func : FunctionField) { ELGUIEventDelegateParameterType ParamType; if (ULGUIEventDelegateParameterHelper::IsSupportedFunction(Func, ParamType))//show only supported type { FString ParamTypeString = ULGUIEventDelegateParameterHelper::ParameterTypeToName(ParamType, Func); auto FunctionSelectorName = FString::Printf(TEXT("%s(%s)"), *Func->GetName(), *ParamTypeString); MenuBuilder.AddMenuEntry( FUIAction(FExecuteAction::CreateRaw(this, &FLGUIEventDelegateCustomization::OnSelectFunction, Func->GetFName(), ParamType, false, ItemPropertyHandle)), SNew(SHorizontalBox) + SHorizontalBox::Slot() .HAlign(EHorizontalAlignment::HAlign_Left) [ SNew(STextBlock) .Text(FText::FromString(FunctionSelectorName)) .Font(IDetailLayoutBuilder::GetDetailFont()) ] ); if (ParamType == EventParameterType && EventParameterType != ELGUIEventDelegateParameterType::Empty)//if function support native parameter, then draw another button, and show as native parameter { FunctionSelectorName = FString::Printf(TEXT("%s(NativeParameter)"), *Func->GetName()); MenuBuilder.AddMenuEntry( FUIAction(FExecuteAction::CreateRaw(this, &FLGUIEventDelegateCustomization::OnSelectFunction, Func->GetFName(), ParamType, true, ItemPropertyHandle)), SNew(SHorizontalBox) + SHorizontalBox::Slot() .HAlign(EHorizontalAlignment::HAlign_Left) [ SNew(STextBlock) .Text(FText::FromString(FunctionSelectorName)) .Font(IDetailLayoutBuilder::GetDetailFont()) ] ); } } } return MenuBuilder.MakeWidget(); } bool FLGUIEventDelegateCustomization::IsComponentSelectorMenuEnabled(TSharedRef ItemPropertyHandle)const { auto HelperActorHandle = ItemPropertyHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FLGUIEventDelegateData, HelperActor)); UObject* HelperActorObject = nullptr; HelperActorHandle->GetValue(HelperActorObject); return IsValid(HelperActorObject); } bool FLGUIEventDelegateCustomization::IsFunctionSelectorMenuEnabled(TSharedRef ItemPropertyHandle)const { auto HelperActorHandle = ItemPropertyHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FLGUIEventDelegateData, HelperActor)); UObject* HelperActorObject = nullptr; HelperActorHandle->GetValue(HelperActorObject); auto TargetObjectHandle = ItemPropertyHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FLGUIEventDelegateData, TargetObject)); UObject* TargetObject = nullptr; TargetObjectHandle->GetValue(TargetObject); return IsValid(HelperActorObject) && IsValid(TargetObject); } void FLGUIEventDelegateCustomization::OnClickListAdd() { auto EventListHandle = GetEventListHandle(); EventListHandle->AddItem(); UpdateEventsLayout(); } void FLGUIEventDelegateCustomization::OnClickListEmpty() { auto EventListHandle = GetEventListHandle(); EventListHandle->EmptyArray(); UpdateEventsLayout(); } FReply FLGUIEventDelegateCustomization::OnClickAddRemove(bool AddOrRemove, int32 Index, int32 Count) { auto EventListHandle = GetEventListHandle(); if (AddOrRemove) { if (Count == 0) { EventListHandle->AddItem(); } else { if (Index == Count - 1)//current is last, add to last EventListHandle->AddItem(); else EventListHandle->Insert(Index + 1); } } else { if (Count != 0) EventListHandle->DeleteItem(Index); } UpdateEventsLayout(); return FReply::Handled(); } FReply FLGUIEventDelegateCustomization::OnClickCopyPaste(bool CopyOrPaste, int32 Index) { auto EventListHandle = GetEventListHandle(); auto EventDataHandle = EventListHandle->GetElement(Index); if (CopyOrPaste) { CopySourceData.Reset(); EventDataHandle->GetPerObjectValues(CopySourceData); } else { EventDataHandle->SetPerObjectValues(CopySourceData); UpdateEventsLayout(); } return FReply::Handled(); } FReply FLGUIEventDelegateCustomization::OnClickDuplicate(int32 Index) { auto EventListHandle = GetEventListHandle(); auto EventDataHandle = EventListHandle->GetElement(Index); EventListHandle->DuplicateItem(Index); return FReply::Handled(); } FReply FLGUIEventDelegateCustomization::OnClickMoveUpDown(bool UpOrDown, int32 Index) { auto EventListHandle = GetEventListHandle(); if (UpOrDown) { if (Index <= 0) return FReply::Handled(); EventListHandle->SwapItems(Index, Index - 1); } else { uint32 arrayCount; EventListHandle->GetNumElements(arrayCount); if (Index + 1 >= (int32)arrayCount) return FReply::Handled(); EventListHandle->SwapItems(Index, Index + 1); } return FReply::Handled(); } #define SET_VALUE_ON_BUFFER(type)\ auto ParamBuffer = GetBuffer(ParamBufferHandle);\ FMemoryReader Reader(ParamBuffer);\ type Value;\ Reader << Value;\ ValueHandle->SetValue(Value); TSharedRef FLGUIEventDelegateCustomization::DrawFunctionParameter(TSharedRef InDataContainerHandle, ELGUIEventDelegateParameterType InFunctionParameterType, UFunction* InFunction) { auto ParamBufferHandle = InDataContainerHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FLGUIEventDelegateData, ParamBuffer)); if (InFunctionParameterType != ELGUIEventDelegateParameterType::None)//None means not select function yet { switch (InFunctionParameterType) { default: case ELGUIEventDelegateParameterType::Empty: { ClearValueBuffer(InDataContainerHandle); ClearReferenceValue(InDataContainerHandle); return SNew(SBox) .MinDesiredWidth(500) .VAlign(EVerticalAlignment::VAlign_Center) [ SNew(STextBlock) .Text(LOCTEXT("(No parameter)", "(No parameter)")) .Font(IDetailLayoutBuilder::GetDetailFont()) ] ; } break; case ELGUIEventDelegateParameterType::Bool: { ClearReferenceValue(InDataContainerHandle); SetBufferLength(ParamBufferHandle, 1); auto ValueHandle = InDataContainerHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FLGUIEventDelegateData, BoolValue)); auto ParamBuffer = GetBuffer(ParamBufferHandle); bool Value = ParamBuffer[0] == 1; ValueHandle->SetValue(Value); ValueHandle->SetOnPropertyValueChanged(FSimpleDelegate::CreateSP(this, &FLGUIEventDelegateCustomization::BoolValueChange, ValueHandle, ParamBufferHandle)); return ValueHandle->CreatePropertyValueWidget(); } break; case ELGUIEventDelegateParameterType::Float: { ClearReferenceValue(InDataContainerHandle); SetBufferLength(ParamBufferHandle, 4); auto ValueHandle = InDataContainerHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FLGUIEventDelegateData, FloatValue)); SET_VALUE_ON_BUFFER(float); ValueHandle->SetOnPropertyValueChanged(FSimpleDelegate::CreateSP(this, &FLGUIEventDelegateCustomization::FloatValueChange, ValueHandle, ParamBufferHandle)); return ValueHandle->CreatePropertyValueWidget(); } break; case ELGUIEventDelegateParameterType::Double: { ClearReferenceValue(InDataContainerHandle); SetBufferLength(ParamBufferHandle, 8); auto ValueHandle = InDataContainerHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FLGUIEventDelegateData, DoubleValue)); SET_VALUE_ON_BUFFER(double); ValueHandle->SetOnPropertyValueChanged(FSimpleDelegate::CreateSP(this, &FLGUIEventDelegateCustomization::DoubleValueChange, ValueHandle, ParamBufferHandle)); return ValueHandle->CreatePropertyValueWidget(); } break; case ELGUIEventDelegateParameterType::Int8: { ClearReferenceValue(InDataContainerHandle); SetBufferLength(ParamBufferHandle, 1); auto ValueHandle = InDataContainerHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FLGUIEventDelegateData, Int8Value)); SET_VALUE_ON_BUFFER(int8); ValueHandle->SetOnPropertyValueChanged(FSimpleDelegate::CreateSP(this, &FLGUIEventDelegateCustomization::Int8ValueChange, ValueHandle, ParamBufferHandle)); return ValueHandle->CreatePropertyValueWidget(); } break; case ELGUIEventDelegateParameterType::UInt8: { ClearReferenceValue(InDataContainerHandle); SetBufferLength(ParamBufferHandle, 1); auto ValueHandle = InDataContainerHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FLGUIEventDelegateData, UInt8Value)); SET_VALUE_ON_BUFFER(uint8); if (auto enumValue = ULGUIEventDelegateParameterHelper::GetEnumParameter(InFunction)) { return SNew(SHorizontalBox) + SHorizontalBox::Slot() .VAlign(VAlign_Center) .FillWidth(1.0f) .Padding(0.0f, 2.0f) [ SNew(SBox) .MinDesiredWidth(500) [ SNew(SEnumComboBox, enumValue) .CurrentValue(this, &FLGUIEventDelegateCustomization::GetEnumValue, ValueHandle) .OnEnumSelectionChanged(this, &FLGUIEventDelegateCustomization::EnumValueChange, ValueHandle, ParamBufferHandle) ] ] ; } else { ValueHandle->SetOnPropertyValueChanged(FSimpleDelegate::CreateSP(this, &FLGUIEventDelegateCustomization::UInt8ValueChange, ValueHandle, ParamBufferHandle)); return ValueHandle->CreatePropertyValueWidget(); } } break; case ELGUIEventDelegateParameterType::Int16: { ClearReferenceValue(InDataContainerHandle); SetBufferLength(ParamBufferHandle, 2); auto ValueHandle = InDataContainerHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FLGUIEventDelegateData, Int16Value)); SET_VALUE_ON_BUFFER(int16); ValueHandle->SetOnPropertyValueChanged(FSimpleDelegate::CreateSP(this, &FLGUIEventDelegateCustomization::Int16ValueChange, ValueHandle, ParamBufferHandle)); return ValueHandle->CreatePropertyValueWidget(); } break; case ELGUIEventDelegateParameterType::UInt16: { ClearReferenceValue(InDataContainerHandle); SetBufferLength(ParamBufferHandle, 2); auto ValueHandle = InDataContainerHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FLGUIEventDelegateData, UInt16Value)); SET_VALUE_ON_BUFFER(uint16); ValueHandle->SetOnPropertyValueChanged(FSimpleDelegate::CreateSP(this, &FLGUIEventDelegateCustomization::UInt16ValueChange, ValueHandle, ParamBufferHandle)); return ValueHandle->CreatePropertyValueWidget(); } break; case ELGUIEventDelegateParameterType::Int32: { ClearReferenceValue(InDataContainerHandle); SetBufferLength(ParamBufferHandle, 4); auto ValueHandle = InDataContainerHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FLGUIEventDelegateData, Int32Value)); SET_VALUE_ON_BUFFER(int32); ValueHandle->SetOnPropertyValueChanged(FSimpleDelegate::CreateSP(this, &FLGUIEventDelegateCustomization::Int32ValueChange, ValueHandle, ParamBufferHandle)); return ValueHandle->CreatePropertyValueWidget(); } break; case ELGUIEventDelegateParameterType::UInt32: { ClearReferenceValue(InDataContainerHandle); SetBufferLength(ParamBufferHandle, 4); auto ValueHandle = InDataContainerHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FLGUIEventDelegateData, UInt32Value)); SET_VALUE_ON_BUFFER(uint32); ValueHandle->SetOnPropertyValueChanged(FSimpleDelegate::CreateSP(this, &FLGUIEventDelegateCustomization::UInt32ValueChange, ValueHandle, ParamBufferHandle)); return ValueHandle->CreatePropertyValueWidget(); } break; case ELGUIEventDelegateParameterType::Int64: { ClearReferenceValue(InDataContainerHandle); SetBufferLength(ParamBufferHandle, 8); auto ValueHandle = InDataContainerHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FLGUIEventDelegateData, Int64Value)); SET_VALUE_ON_BUFFER(int64); ValueHandle->SetOnPropertyValueChanged(FSimpleDelegate::CreateSP(this, &FLGUIEventDelegateCustomization::Int64ValueChange, ValueHandle, ParamBufferHandle)); return ValueHandle->CreatePropertyValueWidget(); } break; case ELGUIEventDelegateParameterType::UInt64: { ClearReferenceValue(InDataContainerHandle); SetBufferLength(ParamBufferHandle, 8); auto ValueHandle = InDataContainerHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FLGUIEventDelegateData, UInt64Value)); SET_VALUE_ON_BUFFER(uint64); ValueHandle->SetOnPropertyValueChanged(FSimpleDelegate::CreateSP(this, &FLGUIEventDelegateCustomization::UInt64ValueChange, ValueHandle, ParamBufferHandle)); return ValueHandle->CreatePropertyValueWidget(); } break; case ELGUIEventDelegateParameterType::Vector2: { ClearReferenceValue(InDataContainerHandle); SetBufferLength(ParamBufferHandle, 8); auto ValueHandle = InDataContainerHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FLGUIEventDelegateData, Vector2Value)); SET_VALUE_ON_BUFFER(FVector2D); return SNew(SHorizontalBox) +SHorizontalBox::Slot() .VAlign(VAlign_Center) .FillWidth(1.0f) .Padding(0.0f, 2.0f) [ SNew(SLGUIVectorInputBox) .AllowSpin(false) .bColorAxisLabels(true) .EnableX(true) .EnableY(true) .ShowX(true) .ShowY(true) .X(this, &FLGUIEventDelegateCustomization::Vector2GetItemValue, 0, ValueHandle, ParamBufferHandle) .Y(this, &FLGUIEventDelegateCustomization::Vector2GetItemValue, 1, ValueHandle, ParamBufferHandle) .OnXCommitted(this, &FLGUIEventDelegateCustomization::Vector2ItemValueChange, 0, ValueHandle, ParamBufferHandle) .OnYCommitted(this, &FLGUIEventDelegateCustomization::Vector2ItemValueChange, 1, ValueHandle, ParamBufferHandle) ] ; } break; case ELGUIEventDelegateParameterType::Vector3: { ClearReferenceValue(InDataContainerHandle); SetBufferLength(ParamBufferHandle, 12); auto ValueHandle = InDataContainerHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FLGUIEventDelegateData, Vector3Value)); SET_VALUE_ON_BUFFER(FVector); return SNew(SHorizontalBox) +SHorizontalBox::Slot() .VAlign(VAlign_Center) .FillWidth(1.0f) .Padding(0.0f, 2.0f) [ SNew(SLGUIVectorInputBox) .AllowSpin(false) .bColorAxisLabels(true) .EnableX(true) .EnableY(true) .EnableZ(true) .ShowX(true) .ShowY(true) .ShowZ(true) .X(this, &FLGUIEventDelegateCustomization::Vector3GetItemValue, 0, ValueHandle, ParamBufferHandle) .Y(this, &FLGUIEventDelegateCustomization::Vector3GetItemValue, 1, ValueHandle, ParamBufferHandle) .Z(this, &FLGUIEventDelegateCustomization::Vector3GetItemValue, 2, ValueHandle, ParamBufferHandle) .OnXCommitted(this, &FLGUIEventDelegateCustomization::Vector3ItemValueChange, 0, ValueHandle, ParamBufferHandle) .OnYCommitted(this, &FLGUIEventDelegateCustomization::Vector3ItemValueChange, 1, ValueHandle, ParamBufferHandle) .OnZCommitted(this, &FLGUIEventDelegateCustomization::Vector3ItemValueChange, 2, ValueHandle, ParamBufferHandle) ] ; } break; case ELGUIEventDelegateParameterType::Vector4: { ClearReferenceValue(InDataContainerHandle); SetBufferLength(ParamBufferHandle, 16); auto ValueHandle = InDataContainerHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FLGUIEventDelegateData, Vector4Value)); SET_VALUE_ON_BUFFER(FVector4); return SNew(SHorizontalBox) +SHorizontalBox::Slot() .VAlign(VAlign_Center) .FillWidth(1.0f) .Padding(0.0f, 2.0f) [ SNew(SLGUIVectorInputBox) .AllowSpin(false) .bColorAxisLabels(true) .EnableX(true) .EnableY(true) .EnableZ(true) .EnableW(true) .ShowX(true) .ShowY(true) .ShowZ(true) .ShowW(true) .X(this, &FLGUIEventDelegateCustomization::Vector4GetItemValue, 0, ValueHandle, ParamBufferHandle) .Y(this, &FLGUIEventDelegateCustomization::Vector4GetItemValue, 1, ValueHandle, ParamBufferHandle) .Z(this, &FLGUIEventDelegateCustomization::Vector4GetItemValue, 2, ValueHandle, ParamBufferHandle) .W(this, &FLGUIEventDelegateCustomization::Vector4GetItemValue, 3, ValueHandle, ParamBufferHandle) .OnXCommitted(this, &FLGUIEventDelegateCustomization::Vector4ItemValueChange, 0, ValueHandle, ParamBufferHandle) .OnYCommitted(this, &FLGUIEventDelegateCustomization::Vector4ItemValueChange, 1, ValueHandle, ParamBufferHandle) .OnZCommitted(this, &FLGUIEventDelegateCustomization::Vector4ItemValueChange, 2, ValueHandle, ParamBufferHandle) .OnWCommitted(this, &FLGUIEventDelegateCustomization::Vector4ItemValueChange, 3, ValueHandle, ParamBufferHandle) ] ; } break; case ELGUIEventDelegateParameterType::Color: { ClearReferenceValue(InDataContainerHandle); SetBufferLength(ParamBufferHandle, 4); auto ValueHandle = InDataContainerHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FLGUIEventDelegateData, ColorValue)); auto ParamBuffer = GetBuffer(ParamBufferHandle); FMemoryReader Reader(ParamBuffer); FColor Value; Reader << Value; ValueHandle->SetValueFromFormattedString(Value.ToString()); return SNew(SHorizontalBox) + SHorizontalBox::Slot() .VAlign(VAlign_Center) .Padding(0.0f, 2.0f) [ // Displays the color with alpha unless it is ignored SAssignNew(ColorPickerParentWidget, SColorBlock) .Color(this, &FLGUIEventDelegateCustomization::LinearColorGetValue, false, ValueHandle, ParamBufferHandle) .ShowBackgroundForAlpha(true) .AlphaDisplayMode(EColorBlockAlphaDisplayMode::Separate) .OnMouseButtonDown(this, &FLGUIEventDelegateCustomization::OnMouseButtonDownColorBlock, false, ValueHandle, ParamBufferHandle) .Size(FVector2D(35.0f, 12.0f)) ] + SHorizontalBox::Slot() .VAlign(VAlign_Center) .Padding(0.0f, 2.0f) [ // Displays the color without alpha SNew(SColorBlock) .Color(this, &FLGUIEventDelegateCustomization::LinearColorGetValue, false, ValueHandle, ParamBufferHandle) .ShowBackgroundForAlpha(false) .AlphaDisplayMode(EColorBlockAlphaDisplayMode::Ignore) .OnMouseButtonDown(this, &FLGUIEventDelegateCustomization::OnMouseButtonDownColorBlock, false, ValueHandle, ParamBufferHandle) .Size(FVector2D(35.0f, 12.0f)) ]; ; } break; case ELGUIEventDelegateParameterType::LinearColor: { ClearReferenceValue(InDataContainerHandle); SetBufferLength(ParamBufferHandle, 16); auto ValueHandle = InDataContainerHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FLGUIEventDelegateData, LinearColorValue)); SET_VALUE_ON_BUFFER(FLinearColor); return SNew(SHorizontalBox) + SHorizontalBox::Slot() .VAlign(VAlign_Center) .Padding(0.0f, 2.0f) [ // Displays the color with alpha unless it is ignored SAssignNew(ColorPickerParentWidget, SColorBlock) .Color(this, &FLGUIEventDelegateCustomization::LinearColorGetValue, true, ValueHandle, ParamBufferHandle) .ShowBackgroundForAlpha(true) .AlphaDisplayMode(EColorBlockAlphaDisplayMode::Separate) .OnMouseButtonDown(this, &FLGUIEventDelegateCustomization::OnMouseButtonDownColorBlock, true, ValueHandle, ParamBufferHandle) .Size(FVector2D(35.0f, 12.0f)) ] + SHorizontalBox::Slot() .VAlign(VAlign_Center) .Padding(0.0f, 2.0f) [ // Displays the color without alpha SNew(SColorBlock) .Color(this, &FLGUIEventDelegateCustomization::LinearColorGetValue, true, ValueHandle, ParamBufferHandle) .ShowBackgroundForAlpha(false) .AlphaDisplayMode(EColorBlockAlphaDisplayMode::Ignore) .OnMouseButtonDown(this, &FLGUIEventDelegateCustomization::OnMouseButtonDownColorBlock, true, ValueHandle, ParamBufferHandle) .Size(FVector2D(35.0f, 12.0f)) ]; ; } break; case ELGUIEventDelegateParameterType::Quaternion: { ClearReferenceValue(InDataContainerHandle); SetBufferLength(ParamBufferHandle, 16); auto ValueHandle = InDataContainerHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FLGUIEventDelegateData, QuatValue)); SET_VALUE_ON_BUFFER(FQuat); return SNew(SHorizontalBox) +SHorizontalBox::Slot() .VAlign(VAlign_Center) .FillWidth(1.0f) .Padding(0.0f, 2.0f) [ SNew(SLGUIVectorInputBox) .AllowSpin(false) .bColorAxisLabels(true) .EnableX(true) .EnableY(true) .EnableZ(true) .EnableW(true) .ShowX(true) .ShowY(true) .ShowZ(true) .ShowW(true) .X(this, &FLGUIEventDelegateCustomization::Vector4GetItemValue, 0, ValueHandle, ParamBufferHandle) .Y(this, &FLGUIEventDelegateCustomization::Vector4GetItemValue, 1, ValueHandle, ParamBufferHandle) .Z(this, &FLGUIEventDelegateCustomization::Vector4GetItemValue, 2, ValueHandle, ParamBufferHandle) .W(this, &FLGUIEventDelegateCustomization::Vector4GetItemValue, 3, ValueHandle, ParamBufferHandle) .OnXCommitted(this, &FLGUIEventDelegateCustomization::Vector4ItemValueChange, 0, ValueHandle, ParamBufferHandle) .OnYCommitted(this, &FLGUIEventDelegateCustomization::Vector4ItemValueChange, 1, ValueHandle, ParamBufferHandle) .OnZCommitted(this, &FLGUIEventDelegateCustomization::Vector4ItemValueChange, 2, ValueHandle, ParamBufferHandle) .OnWCommitted(this, &FLGUIEventDelegateCustomization::Vector4ItemValueChange, 3, ValueHandle, ParamBufferHandle) ] ; } break; case ELGUIEventDelegateParameterType::String: { ClearReferenceValue(InDataContainerHandle); auto ValueHandle = InDataContainerHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FLGUIEventDelegateData, StringValue)); SET_VALUE_ON_BUFFER(FString); ValueHandle->SetOnPropertyValueChanged(FSimpleDelegate::CreateSP(this, &FLGUIEventDelegateCustomization::StringValueChange, ValueHandle, ParamBufferHandle)); return ValueHandle->CreatePropertyValueWidget(); } break; case ELGUIEventDelegateParameterType::Name: { ClearReferenceValue(InDataContainerHandle); auto ValueHandle = InDataContainerHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FLGUIEventDelegateData, NameValue)); SET_VALUE_ON_BUFFER(FName); ValueHandle->SetOnPropertyValueChanged(FSimpleDelegate::CreateSP(this, &FLGUIEventDelegateCustomization::NameValueChange, ValueHandle, ParamBufferHandle)); return ValueHandle->CreatePropertyValueWidget(); } case ELGUIEventDelegateParameterType::Text: { ClearReferenceValue(InDataContainerHandle); auto ValueHandle = InDataContainerHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FLGUIEventDelegateData, TextValue)); SET_VALUE_ON_BUFFER(FText); ValueHandle->SetOnPropertyValueChanged(FSimpleDelegate::CreateSP(this, &FLGUIEventDelegateCustomization::TextValueChange, ValueHandle, ParamBufferHandle)); TSharedRef EditableTextProperty = MakeShareable(new FLGUIEditableTextPropertyHandle(ValueHandle.ToSharedRef(), PropertyUtilites)); const bool bIsMultiLine = EditableTextProperty->IsMultiLineText(); return SNew(SHorizontalBox) + SHorizontalBox::Slot() .VAlign(VAlign_Center) .FillWidth(1.0f) .Padding(0.0f, 2.0f) [ SNew(SBox) .MinDesiredWidth(bIsMultiLine ? 250.f : 125.f) .MaxDesiredWidth(600) [ SNew(STextPropertyEditableTextBox, EditableTextProperty) .Font(FAppStyle::GetFontStyle("PropertyWindow.NormalFont")) .AutoWrapText(true) ] ] ; } case ELGUIEventDelegateParameterType::PointerEvent: { ClearValueBuffer(InDataContainerHandle); ClearReferenceValue(InDataContainerHandle); return SNew(SBox) .MinDesiredWidth(500) [ SNew(STextBlock) .Text(LOCTEXT("PointerEventDataNotEditableError", "(PointerEventData not editable! You can only pass native parameter!)")) .WrappingPolicy(ETextWrappingPolicy::AllowPerCharacterWrapping) .AutoWrapText(true) .ColorAndOpacity(FLinearColor(FColor(255, 0, 0, 255))) .Font(IDetailLayoutBuilder::GetDetailFont()) ]; } break; case ELGUIEventDelegateParameterType::Object: case ELGUIEventDelegateParameterType::Actor: case ELGUIEventDelegateParameterType::Class: { return SNew(SBox) .MinDesiredWidth(500) [ DrawFunctionReferenceParameter(InDataContainerHandle, InFunctionParameterType, InFunction) ]; } break; case ELGUIEventDelegateParameterType::Rotator: { ClearReferenceValue(InDataContainerHandle); SetBufferLength(ParamBufferHandle, 12); auto ValueHandle = InDataContainerHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FLGUIEventDelegateData, RotatorValue)); SET_VALUE_ON_BUFFER(FRotator); TSharedPtr> TypeInterface; if (FUnitConversion::Settings().ShouldDisplayUnits()) { TypeInterface = MakeShareable(new TNumericUnitTypeInterface(EUnit::Degrees)); } return SNew(SHorizontalBox) + SHorizontalBox::Slot() .VAlign(VAlign_Center) .FillWidth(1.0f) .Padding(0.0f, 2.0f) [ SNew(SRotatorInputBox) .AllowSpin(false) .bColorAxisLabels(true) .Roll(this, &FLGUIEventDelegateCustomization::RotatorGetItemValue, 0, ValueHandle, ParamBufferHandle) .Pitch(this, &FLGUIEventDelegateCustomization::RotatorGetItemValue, 1, ValueHandle, ParamBufferHandle) .Yaw(this, &FLGUIEventDelegateCustomization::RotatorGetItemValue, 2, ValueHandle, ParamBufferHandle) .OnRollCommitted(this, &FLGUIEventDelegateCustomization::RotatorValueChange, 0, ValueHandle, ParamBufferHandle) .OnPitchCommitted(this, &FLGUIEventDelegateCustomization::RotatorValueChange, 1, ValueHandle, ParamBufferHandle) .OnYawCommitted(this, &FLGUIEventDelegateCustomization::RotatorValueChange, 2, ValueHandle, ParamBufferHandle) .TypeInterface(TypeInterface) ] ; } break; } } else { ClearValueBuffer(InDataContainerHandle); ClearReferenceValue(InDataContainerHandle); return SNew(STextBlock) .Font(IDetailLayoutBuilder::GetDetailFont()) .Text(LOCTEXT("(Not handled)", "(Not handled)")); } } //function's parameter editor TSharedRef FLGUIEventDelegateCustomization::DrawFunctionReferenceParameter(TSharedRef InDataContainerHandle, ELGUIEventDelegateParameterType FunctionParameterType, UFunction* InFunction) { auto ParamBufferHandle = InDataContainerHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FLGUIEventDelegateData, ParamBuffer)); TSharedPtr ParameterContent; switch (FunctionParameterType) { case ELGUIEventDelegateParameterType::Object: { ClearValueBuffer(InDataContainerHandle); return SNew(SObjectPropertyEntryBox) .IsEnabled(true) .AllowedClass(ULGUIEventDelegateParameterHelper::GetObjectParameterClass(InFunction)) .PropertyHandle(InDataContainerHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FLGUIEventDelegateData, ReferenceObject))) .AllowClear(true) .ToolTipText(LOCTEXT("UObjectTips", "UObject only referece asset, dont use for HelperActor")) .OnObjectChanged(this, &FLGUIEventDelegateCustomization::ObjectValueChange, ParamBufferHandle, InDataContainerHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FLGUIEventDelegateData, ReferenceObject)), true); } break; case ELGUIEventDelegateParameterType::Actor: { ClearValueBuffer(InDataContainerHandle); return SNew(SObjectPropertyEntryBox) .IsEnabled(true) .AllowedClass(ULGUIEventDelegateParameterHelper::GetObjectParameterClass(InFunction)) .PropertyHandle(InDataContainerHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FLGUIEventDelegateData, ReferenceObject))) .AllowClear(true) .OnObjectChanged(this, &FLGUIEventDelegateCustomization::ObjectValueChange, ParamBufferHandle, InDataContainerHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FLGUIEventDelegateData, ReferenceObject)), false); } break; case ELGUIEventDelegateParameterType::Class: { auto MetaClass = ULGUIEventDelegateParameterHelper::GetClassParameterClass(InFunction); auto ValueHandle = InDataContainerHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FLGUIEventDelegateData, ReferenceObject)); ClearValueBuffer(InDataContainerHandle); return SNew(SClassPropertyEntryBox) .IsEnabled(true) .AllowAbstract(true) .AllowNone(true) .MetaClass(MetaClass) .SelectedClass(this, &FLGUIEventDelegateCustomization::GetClassValue, ValueHandle) .OnSetClass(this, &FLGUIEventDelegateCustomization::ClassValueChange, ValueHandle); } break; default: break; } return SNew(STextBlock) .Font(IDetailLayoutBuilder::GetDetailFont()) .Text(LOCTEXT("(Not handled)", "(Not handled)")); } void FLGUIEventDelegateCustomization::ObjectValueChange(const FAssetData& InObj, TSharedPtr BufferHandle, TSharedPtr ObjectReferenceHandle, bool ObjectOrActor) { if (ObjectOrActor) { //ObjectReference is not for HelperActor reference if (InObj.IsValid() && InObj.GetClass()->IsChildOf(AActor::StaticClass())) { UE_LOG(LGUIEditor, Error, TEXT("Please use Actor type for referece Actor, UObject is for asset object referece")); AActor* NullActor = nullptr; ObjectReferenceHandle->SetValue(NullActor); } else { ObjectReferenceHandle->SetValue(InObj); } } else { ObjectReferenceHandle->SetValue(InObj); } } const UClass* FLGUIEventDelegateCustomization::GetClassValue(TSharedPtr ClassReferenceHandle)const { UObject* referenceClassObject = nullptr; ClassReferenceHandle->GetValue(referenceClassObject); return (UClass*)referenceClassObject; } void FLGUIEventDelegateCustomization::ClassValueChange(const UClass* InClass, TSharedPtr ClassReferenceHandle) { ClassReferenceHandle->SetValue(InClass); } void FLGUIEventDelegateCustomization::EnumValueChange(int32 InValue, ESelectInfo::Type SelectionType, TSharedPtr ValueHandle, TSharedPtr BufferHandle) { uint8 Value = (uint8)InValue; ValueHandle->SetValue(Value); UInt8ValueChange(ValueHandle, BufferHandle); } #define SET_BUFFER_ON_VALUE(type)\ type Value;\ ValueHandle->GetValue(Value);\ FBufferArchive ToBinary;\ ToBinary << Value;\ SetBufferValue(BufferHandle, ToBinary); void FLGUIEventDelegateCustomization::BoolValueChange(TSharedPtr ValueHandle, TSharedPtr BufferHandle) { bool Value; ValueHandle->GetValue(Value); TArray Buffer; Buffer.Add(Value ? 1 : 0); SetBufferValue(BufferHandle, Buffer); } void FLGUIEventDelegateCustomization::FloatValueChange(TSharedPtr ValueHandle, TSharedPtr BufferHandle) { SET_BUFFER_ON_VALUE(float); } void FLGUIEventDelegateCustomization::DoubleValueChange(TSharedPtr ValueHandle, TSharedPtr BufferHandle) { SET_BUFFER_ON_VALUE(double); } void FLGUIEventDelegateCustomization::Int8ValueChange(TSharedPtr ValueHandle, TSharedPtr BufferHandle) { SET_BUFFER_ON_VALUE(int8); } void FLGUIEventDelegateCustomization::UInt8ValueChange(TSharedPtr ValueHandle, TSharedPtr BufferHandle) { SET_BUFFER_ON_VALUE(uint8); } void FLGUIEventDelegateCustomization::Int16ValueChange(TSharedPtr ValueHandle, TSharedPtr BufferHandle) { SET_BUFFER_ON_VALUE(int16); } void FLGUIEventDelegateCustomization::UInt16ValueChange(TSharedPtr ValueHandle, TSharedPtr BufferHandle) { SET_BUFFER_ON_VALUE(uint16); } void FLGUIEventDelegateCustomization::Int32ValueChange(TSharedPtr ValueHandle, TSharedPtr BufferHandle) { SET_BUFFER_ON_VALUE(int32); } void FLGUIEventDelegateCustomization::UInt32ValueChange(TSharedPtr ValueHandle, TSharedPtr BufferHandle) { SET_BUFFER_ON_VALUE(uint32); } void FLGUIEventDelegateCustomization::Int64ValueChange(TSharedPtr ValueHandle, TSharedPtr BufferHandle) { SET_BUFFER_ON_VALUE(int64); } void FLGUIEventDelegateCustomization::UInt64ValueChange(TSharedPtr ValueHandle, TSharedPtr BufferHandle) { SET_BUFFER_ON_VALUE(uint64); } void FLGUIEventDelegateCustomization::StringValueChange(TSharedPtr ValueHandle, TSharedPtr BufferHandle) { SET_BUFFER_ON_VALUE(FString); } void FLGUIEventDelegateCustomization::NameValueChange(TSharedPtr ValueHandle, TSharedPtr BufferHandle) { SET_BUFFER_ON_VALUE(FName); } void FLGUIEventDelegateCustomization::TextValueChange(TSharedPtr ValueHandle, TSharedPtr BufferHandle) { SET_BUFFER_ON_VALUE(FText); } void FLGUIEventDelegateCustomization::Vector2ItemValueChange(float NewValue, ETextCommit::Type CommitInfo, int AxisType, TSharedPtr ValueHandle, TSharedPtr BufferHandle) { FVector2D Value; ValueHandle->GetValue(Value); switch (AxisType) { case 0: Value.X = NewValue; break; case 1: Value.Y = NewValue; break; } ValueHandle->SetValue(Value); FBufferArchive ToBinary; ToBinary << Value; SetBufferValue(BufferHandle, ToBinary); } TOptional FLGUIEventDelegateCustomization::Vector2GetItemValue(int AxisType, TSharedPtr ValueHandle, TSharedPtr BufferHandle)const { FVector2D Value; ValueHandle->GetValue(Value); switch (AxisType) { default: case 0: return Value.X; case 1: return Value.Y; } } void FLGUIEventDelegateCustomization::Vector3ItemValueChange(float NewValue, ETextCommit::Type CommitInfo, int AxisType, TSharedPtr ValueHandle, TSharedPtr BufferHandle) { FVector Value; ValueHandle->GetValue(Value); switch (AxisType) { case 0: Value.X = NewValue; break; case 1: Value.Y = NewValue; break; case 2: Value.Z = NewValue; break; } ValueHandle->SetValue(Value); FBufferArchive ToBinary; ToBinary << Value; SetBufferValue(BufferHandle, ToBinary); } TOptional FLGUIEventDelegateCustomization::Vector3GetItemValue(int AxisType, TSharedPtr ValueHandle, TSharedPtr BufferHandle)const { FVector Value; ValueHandle->GetValue(Value); switch (AxisType) { default: case 0: return Value.X; case 1: return Value.Y; case 2: return Value.Z; } } void FLGUIEventDelegateCustomization::Vector4ItemValueChange(float NewValue, ETextCommit::Type CommitInfo, int AxisType, TSharedPtr ValueHandle, TSharedPtr BufferHandle) { FVector4 Value; ValueHandle->GetValue(Value); switch (AxisType) { case 0: Value.X = NewValue; break; case 1: Value.Y = NewValue; break; case 2: Value.Z = NewValue; break; case 3: Value.W = NewValue; break; } ValueHandle->SetValue(Value); FBufferArchive ToBinary; ToBinary << Value; SetBufferValue(BufferHandle, ToBinary); } TOptional FLGUIEventDelegateCustomization::Vector4GetItemValue(int AxisType, TSharedPtr ValueHandle, TSharedPtr BufferHandle)const { FVector4 Value; ValueHandle->GetValue(Value); switch (AxisType) { default: case 0: return Value.X; case 1: return Value.Y; case 2: return Value.Z; case 3: return Value.W; } } FLinearColor FLGUIEventDelegateCustomization::LinearColorGetValue(bool bIsLinearColor, TSharedPtr ValueHandle, TSharedPtr BufferHandle)const { if (bIsLinearColor) { FLinearColor Value; FString FormatedString; ValueHandle->GetValueAsFormattedString(FormatedString); Value.InitFromString(FormatedString); return Value; } else { FColor Value; FString FormatedString; ValueHandle->GetValueAsFormattedString(FormatedString); Value.InitFromString(FormatedString); return FLinearColor(Value.R / 255.0f, Value.G / 255.0f, Value.B / 255.0f, Value.A / 255.0f); } } void FLGUIEventDelegateCustomization::LinearColorValueChange(FLinearColor NewValue, bool bIsLinearColor, TSharedPtr ValueHandle, TSharedPtr BufferHandle) { if (bIsLinearColor) { FString FormatedString = NewValue.ToString(); ValueHandle->SetValueFromFormattedString(FormatedString); FBufferArchive ToBinary; ToBinary << NewValue; SetBufferValue(BufferHandle, ToBinary); } else { FColor ColorValue = NewValue.ToFColor(false); FString FormatedString = ColorValue.ToString(); ValueHandle->SetValueFromFormattedString(FormatedString); FBufferArchive ToBinary; ToBinary << ColorValue; SetBufferValue(BufferHandle, ToBinary); } } FReply FLGUIEventDelegateCustomization::OnMouseButtonDownColorBlock(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent, bool bIsLinearColor, TSharedPtr ValueHandle, TSharedPtr BufferHandle) { if (MouseEvent.GetEffectingButton() != EKeys::LeftMouseButton) { return FReply::Unhandled(); } CreateColorPicker(bIsLinearColor, ValueHandle, BufferHandle); return FReply::Handled(); } TOptional FLGUIEventDelegateCustomization::RotatorGetItemValue(int AxisType, TSharedPtr ValueHandle, TSharedPtr BufferHandle)const { FRotator Value; ValueHandle->GetValue(Value); switch (AxisType) { default: case 0: return Value.Roll; case 1: return Value.Pitch; case 2: return Value.Yaw; } } void FLGUIEventDelegateCustomization::RotatorValueChange(float NewValue, ETextCommit::Type CommitInfo, int AxisType, TSharedPtr ValueHandle, TSharedPtr BufferHandle) { FRotator Value; ValueHandle->GetValue(Value); switch (AxisType) { case 0: Value.Roll = NewValue; break; case 1: Value.Pitch = NewValue; break; case 2: Value.Yaw = NewValue; break; } ValueHandle->SetValue(Value); FBufferArchive ToBinary; ToBinary << Value; SetBufferValue(BufferHandle, ToBinary); } void FLGUIEventDelegateCustomization::SetBufferValue(TSharedPtr BufferHandle, const TArray& BufferArray) { auto BufferArrayHandle = BufferHandle->AsArray(); auto bufferCount = BufferArray.Num(); uint32 bufferHandleCount; BufferArrayHandle->GetNumElements(bufferHandleCount); if (bufferCount != (int32)bufferHandleCount) { BufferArrayHandle->EmptyArray(); for (int i = 0; i < bufferCount; i++) { BufferArrayHandle->AddItem(); auto bufferHandle = BufferArrayHandle->GetElement(i); auto buffer = BufferArray[i]; bufferHandle->SetValue(buffer); } } else { for (int i = 0; i < bufferCount; i++) { auto bufferHandle = BufferArrayHandle->GetElement(i); auto buffer = BufferArray[i]; bufferHandle->SetValue(buffer); } } } void FLGUIEventDelegateCustomization::SetBufferLength(TSharedPtr BufferHandle, int32 Count) { auto BufferArrayHandle = BufferHandle->AsArray(); uint32 bufferHandleCount; BufferArrayHandle->GetNumElements(bufferHandleCount); if (Count != (int32)bufferHandleCount) { BufferArrayHandle->EmptyArray(); for (int i = 0; i < Count; i++) { BufferArrayHandle->AddItem(); } } } TArray FLGUIEventDelegateCustomization::GetBuffer(TSharedPtr BufferHandle) { auto BufferArrayHandle = BufferHandle->AsArray(); uint32 bufferHandleCount; BufferArrayHandle->GetNumElements(bufferHandleCount); TArray resultBuffer; resultBuffer.Reserve(bufferHandleCount); for (uint32 i = 0; i < bufferHandleCount; i++) { auto elementHandle = BufferArrayHandle->GetElement(i); uint8 value; elementHandle->GetValue(value); resultBuffer.Add(value); } return resultBuffer; } TArray FLGUIEventDelegateCustomization::GetPropertyBuffer(TSharedPtr BufferHandle) const { auto paramBufferArrayHandle = BufferHandle->AsArray(); uint32 bufferCount; paramBufferArrayHandle->GetNumElements(bufferCount); TArray paramBuffer; for (uint32 i = 0; i < bufferCount; i++) { auto bufferHandle = paramBufferArrayHandle->GetElement(i); uint8 buffer; bufferHandle->GetValue(buffer); paramBuffer.Add(buffer); } return paramBuffer; } int32 FLGUIEventDelegateCustomization::GetEnumValue(TSharedPtr ValueHandle)const { uint8 Value = 0; ValueHandle->GetValue(Value); return Value; } FText FLGUIEventDelegateCustomization::GetTextValue(TSharedPtr ValueHandle)const { FText Value; ValueHandle->GetValue(Value); return Value; } void FLGUIEventDelegateCustomization::SetTextValue(const FText& InText, ETextCommit::Type InCommitType, TSharedPtr ValueHandle) { ValueHandle->SetValue(InText); } void FLGUIEventDelegateCustomization::ClearValueBuffer(TSharedPtr InItemPropertyHandle) { auto handle = InItemPropertyHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FLGUIEventDelegateData, ParamBuffer))->AsArray(); uint32 NumElements = 0; if (handle->GetNumElements(NumElements) == FPropertyAccess::Result::Success && NumElements > 0) { handle->EmptyArray(); } } void FLGUIEventDelegateCustomization::ClearReferenceValue(TSharedPtr InItemPropertyHandle) { ClearObjectValue(InItemPropertyHandle); } void FLGUIEventDelegateCustomization::ClearObjectValue(TSharedPtr InItemPropertyHandle) { auto handle = InItemPropertyHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FLGUIEventDelegateData, ReferenceObject)); UObject* Obj = nullptr; if (handle->GetValue(Obj) == FPropertyAccess::Result::Success && Obj != nullptr) { handle->ResetToDefault(); } } void FLGUIEventDelegateCustomization::OnParameterTypeChange(TSharedRef InItemPropertyHandle) { auto ValueHandle = InItemPropertyHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FLGUIEventDelegateData, BoolValue)); ValueHandle->ResetToDefault(); ValueHandle = InItemPropertyHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FLGUIEventDelegateData, FloatValue)); ValueHandle->ResetToDefault(); ValueHandle = InItemPropertyHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FLGUIEventDelegateData, DoubleValue)); ValueHandle->ResetToDefault(); ValueHandle = InItemPropertyHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FLGUIEventDelegateData, Int8Value)); ValueHandle->ResetToDefault(); ValueHandle = InItemPropertyHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FLGUIEventDelegateData, UInt8Value)); ValueHandle->ResetToDefault(); ValueHandle = InItemPropertyHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FLGUIEventDelegateData, Int16Value)); ValueHandle->ResetToDefault(); ValueHandle = InItemPropertyHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FLGUIEventDelegateData, UInt16Value)); ValueHandle->ResetToDefault(); ValueHandle = InItemPropertyHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FLGUIEventDelegateData, Int32Value)); ValueHandle->ResetToDefault(); ValueHandle = InItemPropertyHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FLGUIEventDelegateData, UInt32Value)); ValueHandle->ResetToDefault(); ValueHandle = InItemPropertyHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FLGUIEventDelegateData, Int64Value)); ValueHandle->ResetToDefault(); ValueHandle = InItemPropertyHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FLGUIEventDelegateData, UInt64Value)); ValueHandle->ResetToDefault(); ValueHandle = InItemPropertyHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FLGUIEventDelegateData, Vector2Value)); ValueHandle->ResetToDefault(); ValueHandle = InItemPropertyHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FLGUIEventDelegateData, Vector3Value)); ValueHandle->ResetToDefault(); ValueHandle = InItemPropertyHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FLGUIEventDelegateData, Vector4Value)); ValueHandle->ResetToDefault(); ValueHandle = InItemPropertyHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FLGUIEventDelegateData, QuatValue)); ValueHandle->ResetToDefault(); ValueHandle = InItemPropertyHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FLGUIEventDelegateData, ColorValue)); ValueHandle->ResetToDefault(); ValueHandle = InItemPropertyHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FLGUIEventDelegateData, LinearColorValue)); ValueHandle->ResetToDefault(); ValueHandle = InItemPropertyHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FLGUIEventDelegateData, RotatorValue)); ValueHandle->ResetToDefault(); } void FLGUIEventDelegateCustomization::CreateColorPicker(bool bIsLinearColor, TSharedPtr ValueHandle, TSharedPtr BufferHandle) { FLinearColor InitialColor = LinearColorGetValue(bIsLinearColor, ValueHandle, BufferHandle); FColorPickerArgs PickerArgs; { PickerArgs.bUseAlpha = true; PickerArgs.bOnlyRefreshOnMouseUp = false; PickerArgs.bOnlyRefreshOnOk = false; PickerArgs.sRGBOverride = bIsLinearColor; PickerArgs.DisplayGamma = TAttribute::Create(TAttribute::FGetter::CreateUObject(GEngine, &UEngine::GetDisplayGamma)); PickerArgs.OnColorCommitted = FOnLinearColorValueChanged::CreateSP(this, &FLGUIEventDelegateCustomization::LinearColorValueChange, bIsLinearColor, ValueHandle, BufferHandle); //PickerArgs.OnColorPickerCancelled = FOnColorPickerCancelled::CreateSP(this, &FColorStructCustomization::OnColorPickerCancelled); //PickerArgs.OnInteractivePickBegin = FSimpleDelegate::CreateSP(this, &FColorStructCustomization::OnColorPickerInteractiveBegin); //PickerArgs.OnInteractivePickEnd = FSimpleDelegate::CreateSP(this, &FColorStructCustomization::OnColorPickerInteractiveEnd); PickerArgs.InitialColor = InitialColor; PickerArgs.ParentWidget = ColorPickerParentWidget; PickerArgs.OptionalOwningDetailsView = ColorPickerParentWidget; FWidgetPath ParentWidgetPath; if (FSlateApplication::Get().FindPathToWidget(ColorPickerParentWidget.ToSharedRef(), ParentWidgetPath)) { PickerArgs.bOpenAsMenu = FSlateApplication::Get().FindMenuInWidgetPath(ParentWidgetPath).IsValid(); } } OpenColorPicker(PickerArgs); } UE_ENABLE_OPTIMIZATION #undef LOCTEXT_NAMESPACE