GASATHON/Project/Source/Gasa/UI/GasaUserWidget.cpp

311 lines
10 KiB
C++
Raw Normal View History

#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<UWidget>(pUWidget, this);
UPanelWidget *pNewUPanelWidget = Cast<UPanelWidget>(pNewWidget);
if (pNewUPanelWidget)
{
const TArray<UPanelSlot*>& slots = pNewUPanelWidget->GetSlots();
for (int32 iSlotNum = 0; iSlotNum < slots.Num(); ++iSlotNum)
{
slots[iSlotNum]->Content = nullptr;
}
pNewUPanelWidget->ClearChildren();
UPanelWidget *pUPanelWidget = Cast<UPanelWidget>(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<UHorizontalBoxSlot>(pUPanelSlot);
if (pNewUHorizontalBoxSlot)
{
UHorizontalBoxSlot *pUHorizontalBoxSlot = Cast<UHorizontalBoxSlot>(pChildUWidget->Slot);
pNewUHorizontalBoxSlot->SetHorizontalAlignment(pUHorizontalBoxSlot->HorizontalAlignment);
pNewUHorizontalBoxSlot->SetVerticalAlignment(pUHorizontalBoxSlot->VerticalAlignment);
}
USizeBoxSlot *pNewUSizeBoxSlot = Cast<USizeBoxSlot>(pUPanelSlot);
if (pNewUSizeBoxSlot)
{
USizeBoxSlot *pUSizeBoxSlot = Cast<USizeBoxSlot>(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<UWidgetBlueprintGeneratedClass>(LooseParent);
UWidgetBlueprintGeneratedClass* WBG_Class = Cast<UWidgetBlueprintGeneratedClass>(GetClass());
if (WBG_ParentClass == nullptr)
return;
if (WBG_Class == nullptr)
return;
UPackage* Package = WBG_Class->GetPackage();
UWidgetBlueprint* BP = Cast<UWidgetBlueprint>(Package->FindAssetInPackage());
UWidgetTree* WT = BP->WidgetTree;
UPackage* UserParentPackage = WBG_ParentClass->GetPackage();
UWidgetBlueprint* UserParentBP = Cast<UWidgetBlueprint>(UserParentPackage->FindAssetInPackage());
UWidgetTree* UserParentWT = UserParentBP->WidgetTree;
TArray<UWidget*> UserParentWidgets;
UserParentWT->GetAllWidgets(UserParentWidgets);
for (UWidget* UserParentWidget : UserParentWidgets)
{
UWidget* OldWidget = nullptr;
UWidget* Widget = WT->FindWidget(UserParentWidget->GetFName());
TArray<UWidget*> Children;
UPanelWidget* Parent = nullptr;
if (Widget == nullptr)
{
if (UserParentWidget->GetClass()->IsChildOf(UUserWidget::StaticClass()))
Widget = CreateWidget<UUserWidget>(WT, UserParentWidget->GetClass(), UserParentWidget->GetFName());
else
Widget = NewObject<UWidget>(WT, UserParentWidget->GetClass(), UserParentWidget->GetFName(), RF_Transactional, UserParentWidget);
if (WT->RootWidget == nullptr)
{
WT->RootWidget = Widget;
}
else
{
Parent = WT->FindWidget<UPanelWidget>(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<UPanelWidget>(Widget);
if (Panel)
{
Children = Panel->GetAllChildren();
}
OldWidget = Widget;
Widget = DuplicateObject<UWidget>(UserParentWidget, WT, UserParentWidget->GetFName());
}
UPanelWidget* NewPanel = Cast<UPanelWidget>(Widget);
if (NewPanel)
{
const TArray<UPanelSlot*>& 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<UScaleBoxSlot>(PSlot);
UScrollBoxSlot* SlotScroll = Cast<UScrollBoxSlot>(PSlot);
UOverlaySlot* SlotOverlay = Cast<UOverlaySlot>(PSlot);
UHorizontalBoxSlot* SlotHB = Cast<UHorizontalBoxSlot>(PSlot);
USizeBoxSlot* SlotSB = Cast<USizeBoxSlot>(PSlot);
UVerticalBoxSlot* SlobVB = Cast<UVerticalBoxSlot>(PSlot);
if (SlotOverlay)
{
UOverlay* UPW_ParentOverlay = Cast<UOverlay>(UserParentWidget->GetParent());
UOverlaySlot* ParentSlot = Cast<UOverlaySlot>(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<UPanelWidget>(Widget)->AddChild(Child);
UScaleBoxSlot* SlotScale = Cast<UScaleBoxSlot>(PSlot);
UScrollBoxSlot* SlotScroll = Cast<UScrollBoxSlot>(PSlot);
UOverlaySlot* SlotOverlay = Cast<UOverlaySlot>(PSlot);
UHorizontalBoxSlot* SlotHB = Cast<UHorizontalBoxSlot>(PSlot);
USizeBoxSlot* SlotSB = Cast<USizeBoxSlot>(PSlot);
UVerticalBoxSlot* SlobVB = Cast<UVerticalBoxSlot>(PSlot);
// I'm not entirely sure if this is possible this way...
if (SlotOverlay)
{
UOverlay* ParentOverlay = Cast<UOverlay>(OldWidget->GetParent());
UOverlaySlot* ParentSlot = Cast<UOverlaySlot>(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<UUserWidget>())
{
#if WITH_EDITOR
SetDesignerFlags(OwningUserWidget->GetDesignerFlags());
#endif
SetPlayerContext(OwningUserWidget->GetPlayerContext());
}
UWidgetBlueprintGeneratedClass* BGClass = Cast<UWidgetBlueprintGeneratedClass>(GetClass());
// Only do this if this widget is of a blueprint class
if (BGClass)
{
BGClass->InitializeWidget(this);
}
else
{
InitializeNativeClassData();
}
if ( WidgetTree == nullptr )
{
WidgetTree = NewObject<UWidgetTree>(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<UWidgetBlueprintGeneratedClass>(LooseParent);
UPackage* UserParentPackage = WBG_ParentClass->GetPackage();
UWidgetBlueprint* UserParentBP = Cast<UWidgetBlueprint>(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<UWidgetBlueprintGeneratedClass>(LooseParent);
if (WBG_ParentClass == nullptr)
return;
UPackage* UserParentPackage = WBG_ParentClass->GetPackage();
UWidgetBlueprint* UserParentBP = Cast<UWidgetBlueprint>(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<UWidgetBlueprintGeneratedClass>(LooseParent);
UPackage* UserParentPackage = WBG_ParentClass->GetPackage();
UWidgetBlueprint* UserParentBP = Cast<UWidgetBlueprint>(UserParentPackage->FindAssetInPackage());
UWidgetTree* UserParentWT = UserParentBP->WidgetTree;
UserParentBP->OnCompiled().AddLambda( [this](UBlueprint* BP) {
if (this)
{
this->GenerateParentHierarchyFromLooseParent();
}
});
}
#endif
}