Skip to content

Commit

Permalink
Ability to climb up the parent tree for widget blueprint hooking
Browse files Browse the repository at this point in the history
Previously, when the parent type is "Indirect (Child)", you could only choose the direct parent for the widget to attach the new widget to.
Now you can choose the grandparents too.
  • Loading branch information
yeshjho committed Nov 24, 2024
1 parent 04025f8 commit 608af80
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -55,23 +55,26 @@ bool WidgetBlueprintHookParentValidator::ValidateDirectWidget(UWidget* Widget, U
return true;
}

bool WidgetBlueprintHookParentValidator::ValidateIndirectChildWidget(UWidget* Widget, UPanelWidget*& OutPanelWidget, bool bCheckVariableName) {
bool WidgetBlueprintHookParentValidator::ValidateIndirectChildWidget(UWidget* Widget, UPanelWidget*& OutPanelWidget, bool bCheckVariableName, FName ParentNameToCheck) {
if (!ValidateWidgetBase(Widget, bCheckVariableName)) {
return false;
}
if (Widget->Slot == NULL) {
return false;
}
UPanelWidget* ParentPanelWidget = Widget->Slot->Parent;
while (ParentPanelWidget && (!ParentNameToCheck.IsNone() && ParentPanelWidget->GetFName() != ParentNameToCheck)) {
ParentPanelWidget = ParentPanelWidget->GetParent();
}
return ValidateDirectWidget(ParentPanelWidget, OutPanelWidget, false);
}

bool WidgetBlueprintHookParentValidator::ValidateParentWidget(UWidget* Widget, EWidgetBlueprintHookParentType ParentType, UPanelWidget*& OutParentWidget, bool bCheckVariableName) {
bool WidgetBlueprintHookParentValidator::ValidateParentWidget(UWidget* Widget, EWidgetBlueprintHookParentType ParentType, UPanelWidget*& OutParentWidget, bool bCheckVariableName, FName ParentNameToCheck) {
if (ParentType == EWidgetBlueprintHookParentType::Direct) {
return ValidateDirectWidget(Widget, OutParentWidget, bCheckVariableName);
}
if (ParentType == EWidgetBlueprintHookParentType::Indirect_Child) {
return ValidateIndirectChildWidget(Widget, OutParentWidget, bCheckVariableName);
return ValidateIndirectChildWidget(Widget, OutParentWidget, bCheckVariableName, ParentNameToCheck);
}
return false;
}
Expand All @@ -97,6 +100,14 @@ void UWidgetBlueprintHookData::SetParentWidgetName(FName InParentWidgetName) {
ReinitializePanelSlotTemplate();
}

void UWidgetBlueprintHookData::SetIndirectParentWidgetNameToAttachTo(FName InIndirectParentWidgetNameToAttachTo) {
if (ParentWidgetType != EWidgetBlueprintHookParentType::Indirect_Child) {
return;
}
this->IndirectParentWidgetNameToAttachTo = InIndirectParentWidgetNameToAttachTo;
ReinitializePanelSlotTemplate();
}

void UWidgetBlueprintHookData::SetNewWidgetName(FName InNewWidgetName) {
this->NewWidgetName = InNewWidgetName;
ReinitializeNewWidgetTemplate();
Expand Down Expand Up @@ -145,7 +156,7 @@ void UWidgetBlueprintHookData::ReinitializeNewWidgetTemplate() {
}

void UWidgetBlueprintHookData::ReinitializePanelSlotTemplate() {
if (const UPanelWidget* PanelWidget = ResolveParentWidget()) {
if (const UPanelWidget* PanelWidget = ResolveParentWidget(true)) {
PanelSlotClass = UPanelWidgetAccessor::GetPanelSlotClass(PanelWidget);
} else {
PanelSlotClass = NULL;
Expand Down Expand Up @@ -194,7 +205,8 @@ void UWidgetBlueprintHookData::PostEditChangeProperty(FPropertyChangedEvent& Pro
const FName PropertyName = PropertyChangedEvent.MemberProperty->GetFName();
if (PropertyName == GET_MEMBER_NAME_CHECKED(ThisClass, WidgetClass) ||
PropertyName == GET_MEMBER_NAME_CHECKED(ThisClass, ParentWidgetType) ||
PropertyName == GET_MEMBER_NAME_CHECKED(ThisClass, ParentWidgetName)) {
PropertyName == GET_MEMBER_NAME_CHECKED(ThisClass, ParentWidgetName) ||
PropertyName == GET_MEMBER_NAME_CHECKED(ThisClass, IndirectParentWidgetNameToAttachTo)) {
ReinitializePanelSlotTemplate();

} else if (PropertyName == GET_MEMBER_NAME_CHECKED(ThisClass, NewWidgetClass)) {
Expand Down Expand Up @@ -225,7 +237,23 @@ TArray<FString> UWidgetBlueprintHookData::GetParentWidgetNames() const {
return ResultWidgetNames;
}

UPanelWidget* UWidgetBlueprintHookData::ResolveParentWidget() const {
TArray<FString> UWidgetBlueprintHookData::GetIndirectParentWidgetNames() const {
TArray<FString> ResultWidgetNames;

UPanelWidget* ResultParentWidget;

UPanelWidget* ParentPanelWidget = ResolveParentWidget(false);
while (ParentPanelWidget) {
if (WidgetBlueprintHookParentValidator::ValidateDirectWidget(ParentPanelWidget, ResultParentWidget, false)) {
ResultWidgetNames.Add(ParentPanelWidget->GetName());
}
ParentPanelWidget = ParentPanelWidget->GetParent();
}

return ResultWidgetNames;
}

UPanelWidget* UWidgetBlueprintHookData::ResolveParentWidget(bool bFollowIndirectParents) const {
const UWidgetBlueprintGeneratedClass* WidgetBlueprintClass = Cast<UWidgetBlueprintGeneratedClass>(WidgetClass.LoadSynchronous());
if (WidgetBlueprintClass == NULL) {
return NULL;
Expand All @@ -234,7 +262,7 @@ UPanelWidget* UWidgetBlueprintHookData::ResolveParentWidget() const {
UWidget* ParentWidget = WidgetBlueprintClass->GetWidgetTreeArchetype()->FindWidget(ParentWidgetName);

UPanelWidget* OutParentWidget;
if (WidgetBlueprintHookParentValidator::ValidateParentWidget(ParentWidget, ParentWidgetType, OutParentWidget, false)) {
if (WidgetBlueprintHookParentValidator::ValidateParentWidget(ParentWidget, ParentWidgetType, OutParentWidget, false, bFollowIndirectParents ? IndirectParentWidgetNameToAttachTo : FName{})) {
return OutParentWidget;
}
return NULL;
Expand All @@ -258,7 +286,7 @@ void UWidgetBlueprintHookManager::RegisterWidgetBlueprintHook(UWidgetBlueprintHo
return;
}

UPanelWidget* PanelWidget = HookData->ResolveParentWidget();
UPanelWidget* PanelWidget = HookData->ResolveParentWidget(true);

if (PanelWidget == NULL) {
UE_LOG(LogWidgetBlueprintHookManager, Error, TEXT("Failed to hook widget blueprint %s, failed to resolve parent widget %s inside %s"),
Expand Down
22 changes: 18 additions & 4 deletions Mods/SML/Source/SML/Public/Patching/WidgetBlueprintHookManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,10 @@ enum class EWidgetBlueprintHookParentType : uint8 {
};

namespace WidgetBlueprintHookParentValidator {
SML_API bool ValidateParentWidget(UWidget* Widget, EWidgetBlueprintHookParentType ParentType, UPanelWidget*& OutParentWidget, bool bCheckVariableName = true);
SML_API bool ValidateParentWidget(UWidget* Widget, EWidgetBlueprintHookParentType ParentType, UPanelWidget*& OutParentWidget, bool bCheckVariableName = true, FName ParentNameToCheck = FName{});

SML_API bool ValidateDirectWidget(UWidget* Widget, UPanelWidget*& OutPanelWidget, bool bCheckVariableName);
SML_API bool ValidateIndirectChildWidget(UWidget* Widget, UPanelWidget*& OutPanelWidget, bool bCheckVariableName);
SML_API bool ValidateIndirectChildWidget(UWidget* Widget, UPanelWidget*& OutPanelWidget, bool bCheckVariableName, FName ParentNameToCheck = FName{});
SML_API bool ValidateWidgetBase(UWidget* Widget, bool bCheckVariableName);
}

Expand Down Expand Up @@ -76,10 +76,17 @@ class SML_API UWidgetBlueprintHookData : public UDataAsset {
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Advanced")
EWidgetBlueprintHookParentType ParentWidgetType;

/** Name of the parent widget variable to attach this widget to. Must a panel widget. */
/**
* Name of the parent widget variable to attach this widget to. Must a panel widget.
* If ParentWidgetType is Indirect (Child), this is the name of the child widget variable to search for the parents.
*/
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Default", meta = (GetOptions = "GetParentWidgetNames"))
FName ParentWidgetName;

/** Name of the parent widget to attach this widget to when ParentWidgetType is Indirect (Child) */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Advanced", meta = (EditCondition = "ParentWidgetType == EWidgetBlueprintHookParentType::Indirect_Child", GetOptions = "GetIndirectParentWidgetNames"))
FName IndirectParentWidgetNameToAttachTo;

/**
* When not -1, specifies the index in the parent widget Slots array at which the widget will be inserted
* By default the widget will be appended to the array, but you can change the order if needed */
Expand All @@ -100,6 +107,9 @@ class SML_API UWidgetBlueprintHookData : public UDataAsset {

UFUNCTION(BlueprintPure)
TArray<FString> GetParentWidgetNames() const;

UFUNCTION(BlueprintPure)
TArray<FString> GetIndirectParentWidgetNames() const;

/** Updates the blueprint widget class being hooked */
UFUNCTION(BlueprintSetter)
Expand All @@ -119,10 +129,14 @@ class SML_API UWidgetBlueprintHookData : public UDataAsset {
/** Updates the name of the parent widget for this hook */
UFUNCTION(BlueprintSetter)
void SetParentWidgetName(FName InParentWidgetName);

/** Updates the name of the parent widget for this hook when ParentWidgetType is Indirect (Child) */
UFUNCTION(BlueprintSetter)
void SetIndirectParentWidgetNameToAttachTo(FName InIndirectParentWidgetNameToAttachTo);

void ReinitializeNewWidgetTemplate();
void ReinitializePanelSlotTemplate();
UPanelWidget* ResolveParentWidget() const;
UPanelWidget* ResolveParentWidget(bool bFollowIndirectParents = false) const;
};

UCLASS()
Expand Down

0 comments on commit 608af80

Please sign in to comment.