#include "GasaUserWidget.h" #include "Blueprint/WidgetBlueprintGeneratedClass.h" #include "Blueprint/WidgetTree.h" #include "Components/HorizontalBoxSlot.h" #include "Components/Overlay.h" #include "Components/OverlaySlot.h" #include "Components/ScaleBoxSlot.h" #include "Components/ScrollBoxSlot.h" #include "Components/SizeBoxSlot.h" #include "Components/VerticalBoxSlot.h" #if WITH_EDITOR #include "WidgetBlueprint.h" #include "Kismet2/BlueprintEditorUtils.h" #endif #if 0 UWidget* UMyModalDialog::DeepDuplicateWidget(UWidget *pUWidget) { UWidget *pNewWidget = DuplicateObject(pUWidget, this); UPanelWidget *pNewUPanelWidget = Cast(pNewWidget); if (pNewUPanelWidget) { const TArray& slots = pNewUPanelWidget->GetSlots(); for (int32 iSlotNum = 0; iSlotNum < slots.Num(); ++iSlotNum) { slots[iSlotNum]->Content = nullptr; } pNewUPanelWidget->ClearChildren(); UPanelWidget *pUPanelWidget = Cast(pUWidget); for (int ii = 0; ii < pUPanelWidget->GetChildrenCount(); ++ii) { UWidget *pChildUWidget = pUPanelWidget->GetChildAt(ii); UWidget *pNewChildWidget = DeepDuplicateWidget(pChildUWidget); UPanelSlot *pUPanelSlot = pNewUPanelWidget->AddChild(pNewChildWidget); UHorizontalBoxSlot *pNewUHorizontalBoxSlot = Cast(pUPanelSlot); if (pNewUHorizontalBoxSlot) { UHorizontalBoxSlot *pUHorizontalBoxSlot = Cast(pChildUWidget->Slot); pNewUHorizontalBoxSlot->SetHorizontalAlignment(pUHorizontalBoxSlot->HorizontalAlignment); pNewUHorizontalBoxSlot->SetVerticalAlignment(pUHorizontalBoxSlot->VerticalAlignment); } USizeBoxSlot *pNewUSizeBoxSlot = Cast(pUPanelSlot); if (pNewUSizeBoxSlot) { USizeBoxSlot *pUSizeBoxSlot = Cast(pChildUWidget->Slot); pNewUSizeBoxSlot->SetHorizontalAlignment(pUSizeBoxSlot->HorizontalAlignment); pNewUSizeBoxSlot->SetVerticalAlignment(pUSizeBoxSlot->VerticalAlignment); } } } return pNewWidget; } #endif void UGasaUserWidget::OnLooseParentCompiled(UBlueprint* BP) { GenerateParentHierarchyFromLooseParent(); } // This was just an experiment to see how possible it would be to generate a WidgetTree from a parent reference without using the usual blueprint inheritance. void UGasaUserWidget::GenerateParentHierarchyFromLooseParent() { #if WITH_EDITOR UWidgetBlueprintGeneratedClass* WBG_ParentClass = Cast(LooseParent); UWidgetBlueprintGeneratedClass* WBG_Class = Cast(GetClass()); if (WBG_ParentClass == nullptr) return; if (WBG_Class == nullptr) return; UPackage* Package = WBG_Class->GetPackage(); UWidgetBlueprint* BP = Cast(Package->FindAssetInPackage()); UWidgetTree* WT = BP->WidgetTree; UPackage* UserParentPackage = WBG_ParentClass->GetPackage(); UWidgetBlueprint* UserParentBP = Cast(UserParentPackage->FindAssetInPackage()); UWidgetTree* UserParentWT = UserParentBP->WidgetTree; TArray UserParentWidgets; UserParentWT->GetAllWidgets(UserParentWidgets); for (UWidget* UserParentWidget : UserParentWidgets) { UWidget* OldWidget = nullptr; UWidget* Widget = WT->FindWidget(UserParentWidget->GetFName()); TArray Children; UPanelWidget* Parent = nullptr; if (Widget == nullptr) { if (UserParentWidget->GetClass()->IsChildOf(UUserWidget::StaticClass())) Widget = CreateWidget(WT, UserParentWidget->GetClass(), UserParentWidget->GetFName()); else Widget = NewObject(WT, UserParentWidget->GetClass(), UserParentWidget->GetFName(), RF_Transactional, UserParentWidget); if (WT->RootWidget == nullptr) { WT->RootWidget = Widget; } else { Parent = WT->FindWidget(UserParentWidget->GetParent()->GetFName()); } } else { // The widget existed previously (most likely already ran this before or manually created) // Try to preserve widget heiarchy attached to this if possible Parent = Widget->GetParent(); UPanelWidget* Panel = Cast(Widget); if (Panel) { Children = Panel->GetAllChildren(); } OldWidget = Widget; Widget = DuplicateObject(UserParentWidget, WT, UserParentWidget->GetFName()); } UPanelWidget* NewPanel = Cast(Widget); if (NewPanel) { const TArray& Slots = NewPanel->GetSlots(); for (int32 Id = 0; Id < Slots.Num(); ++Id) { Slots[Id]->Content = nullptr; } NewPanel->ClearChildren(); } if (Parent) { UPanelSlot* PSlot = Parent->AddChild(Widget); UScaleBoxSlot* SlotScale = Cast(PSlot); UScrollBoxSlot* SlotScroll = Cast(PSlot); UOverlaySlot* SlotOverlay = Cast(PSlot); UHorizontalBoxSlot* SlotHB = Cast(PSlot); USizeBoxSlot* SlotSB = Cast(PSlot); UVerticalBoxSlot* SlobVB = Cast(PSlot); if (SlotOverlay) { UOverlay* UPW_ParentOverlay = Cast(UserParentWidget->GetParent()); UOverlaySlot* ParentSlot = Cast(UPW_ParentOverlay->GetSlots()[Parent->GetSlots().Num() - 1]); SlotOverlay->SetPadding( ParentSlot->GetPadding()); SlotOverlay->SetHorizontalAlignment( ParentSlot->GetHorizontalAlignment()); SlotOverlay->SetVerticalAlignment( ParentSlot->GetVerticalAlignment()); } } //This may not need to happen since the children check to see if they need to be added back. for (UWidget* Child : Children) { if (UserParentWT->FindWidget(Child->GetFName())) continue; UPanelSlot* PSlot = Cast(Widget)->AddChild(Child); UScaleBoxSlot* SlotScale = Cast(PSlot); UScrollBoxSlot* SlotScroll = Cast(PSlot); UOverlaySlot* SlotOverlay = Cast(PSlot); UHorizontalBoxSlot* SlotHB = Cast(PSlot); USizeBoxSlot* SlotSB = Cast(PSlot); UVerticalBoxSlot* SlobVB = Cast(PSlot); // I'm not entirely sure if this is possible this way... if (SlotOverlay) { UOverlay* ParentOverlay = Cast(OldWidget->GetParent()); UOverlaySlot* ParentSlot = Cast(ParentOverlay->GetSlots()[Parent->GetSlots().Num() - 1]); SlotOverlay->SetPadding( ParentSlot->GetPadding()); SlotOverlay->SetHorizontalAlignment( ParentSlot->GetHorizontalAlignment()); SlotOverlay->SetVerticalAlignment( ParentSlot->GetVerticalAlignment()); } } if (OldWidget) OldWidget->RemoveFromParent(); } BP->Modify(); FBlueprintEditorUtils::MarkBlueprintAsStructurallyModified(BP); #endif } UGasaUserWidget::UGasaUserWidget(FObjectInitializer const& ObjectInitializer) : UUserWidget(ObjectInitializer) { } bool UGasaUserWidget::Initialize() { // If it's not initialized initialize it, as long as it's not the CDO, we never initialize the CDO. if (!bInitialized && !HasAnyFlags(RF_ClassDefaultObject)) { // If this is a sub-widget of another UserWidget, default designer flags and player context to match those of the owning widget if (UUserWidget* OwningUserWidget = GetTypedOuter()) { #if WITH_EDITOR SetDesignerFlags(OwningUserWidget->GetDesignerFlags()); #endif SetPlayerContext(OwningUserWidget->GetPlayerContext()); } UWidgetBlueprintGeneratedClass* BGClass = Cast(GetClass()); // Only do this if this widget is of a blueprint class if (BGClass) { BGClass->InitializeWidget(this); } else { InitializeNativeClassData(); } if ( WidgetTree == nullptr ) { WidgetTree = NewObject(this, TEXT("WidgetTree"), RF_Transient); } else { WidgetTree->SetFlags(RF_Transient); InitializeNamedSlots(); } // For backward compatibility, run the initialize event on widget that doesn't have a player context only when the class authorized it. bool bClassWantsToRunInitialized = BGClass && BGClass->bCanCallInitializedWithoutPlayerContext; if (!IsDesignTime() && (GetPlayerContext().IsValid() || bClassWantsToRunInitialized)) { NativeOnInitialized(); } #if WITH_EDITOR if (LooseParent && bUpdateOnParentCompile) { UWidgetBlueprintGeneratedClass* WBG_ParentClass = Cast(LooseParent); UPackage* UserParentPackage = WBG_ParentClass->GetPackage(); UWidgetBlueprint* UserParentBP = Cast(UserParentPackage->FindAssetInPackage()); UWidgetTree* UserParentWT = UserParentBP->WidgetTree; if ( ! UserParentBP->OnCompiled().IsBoundToObject(this)) { UserParentBP->OnCompiled().AddUObject(this, & ThisClass::OnLooseParentCompiled); } } #endif bInitialized = true; return true; } return false; } void UGasaUserWidget::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) { Super::PostEditChangeProperty(PropertyChangedEvent); FName PropertyName = (PropertyChangedEvent.Property != NULL) ? PropertyChangedEvent.Property->GetFName() : NAME_None; if (PropertyName == GET_MEMBER_NAME_CHECKED(UGasaUserWidget, LooseParent) || PropertyName == GET_MEMBER_NAME_CHECKED(UGasaUserWidget, bUpdateOnParentCompile) ) { #if WITH_EDITOR if (LooseParent && bUpdateOnParentCompile) { UWidgetBlueprintGeneratedClass* WBG_ParentClass = Cast(LooseParent); if (WBG_ParentClass == nullptr) return; UPackage* UserParentPackage = WBG_ParentClass->GetPackage(); UWidgetBlueprint* UserParentBP = Cast(UserParentPackage->FindAssetInPackage()); UWidgetTree* UserParentWT = UserParentBP->WidgetTree; if ( ! UserParentBP->OnCompiled().IsBoundToObject(this)) { UserParentBP->OnCompiled().AddUObject(this, & ThisClass::OnLooseParentCompiled); } } #endif } } void UGasaUserWidget::NativeOnInitialized() { Super::NativeOnInitialized(); } void UGasaUserWidget::NativePreConstruct() { Super::NativePreConstruct(); #if 0 if (LooseParent) { UWidgetBlueprintGeneratedClass* WBG_ParentClass = Cast(LooseParent); UPackage* UserParentPackage = WBG_ParentClass->GetPackage(); UWidgetBlueprint* UserParentBP = Cast(UserParentPackage->FindAssetInPackage()); UWidgetTree* UserParentWT = UserParentBP->WidgetTree; UserParentBP->OnCompiled().AddLambda( [this](UBlueprint* BP) { if (this) { this->GenerateParentHierarchyFromLooseParent(); } }); } #endif }