Widget reparenting done.
This commit is contained in:
@@ -80,17 +80,8 @@ public:
|
|||||||
{
|
{
|
||||||
UWidget* ParentWidget = WingUtils::FindExactlyOneNamed(Parent, AllWidgets, TEXT("Widget"));
|
UWidget* ParentWidget = WingUtils::FindExactlyOneNamed(Parent, AllWidgets, TEXT("Widget"));
|
||||||
if (!ParentWidget) return;
|
if (!ParentWidget) return;
|
||||||
|
if (!WingWidgets::CheckCanBeParent(ParentWidget)) return;
|
||||||
ParentPanel = Cast<UPanelWidget>(ParentWidget);
|
ParentPanel = Cast<UPanelWidget>(ParentWidget);
|
||||||
if (!ParentPanel)
|
|
||||||
{
|
|
||||||
UWingServer::Printf(TEXT("ERROR: '%s' is not a panel widget and cannot have children\n"), *Parent);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!ParentPanel->CanAddMoreChildren())
|
|
||||||
{
|
|
||||||
UWingServer::Printf(TEXT("ERROR: '%s' already has a child and cannot accept more\n"), *Parent);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
85
Plugins/UEWingman/Source/UEWingman/Handlers/Widget_Delete.h
Normal file
85
Plugins/UEWingman/Source/UEWingman/Handlers/Widget_Delete.h
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "CoreMinimal.h"
|
||||||
|
#include "WingServer.h"
|
||||||
|
#include "WingHandler.h"
|
||||||
|
#include "WingFetcher.h"
|
||||||
|
#include "WingUtils.h"
|
||||||
|
#include "WidgetBlueprint.h"
|
||||||
|
#include "Blueprint/WidgetTree.h"
|
||||||
|
#include "Components/PanelWidget.h"
|
||||||
|
#include "Kismet2/BlueprintEditorUtils.h"
|
||||||
|
#include "Widget_Delete.generated.h"
|
||||||
|
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
UCLASS()
|
||||||
|
class UWing_Widget_Delete : public UObject, public IWingHandler
|
||||||
|
{
|
||||||
|
GENERATED_BODY()
|
||||||
|
|
||||||
|
public:
|
||||||
|
UPROPERTY(meta=(Description="Path to the widget, eg /Game/Widgets/WB_Test,widget:MyButton"))
|
||||||
|
FString Widget;
|
||||||
|
|
||||||
|
virtual FString GetDescription() const override
|
||||||
|
{
|
||||||
|
return TEXT("Delete a widget from a Widget Blueprint's widget tree. "
|
||||||
|
"The widget must not have any children.");
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void Handle() override
|
||||||
|
{
|
||||||
|
// Walk to the widget.
|
||||||
|
WingFetcher F;
|
||||||
|
UWidget* TargetWidget = F.Walk(Widget).Cast<UWidget>();
|
||||||
|
if (!TargetWidget) return;
|
||||||
|
|
||||||
|
// Get the widget blueprint and tree from the widget's outer chain.
|
||||||
|
UWidgetBlueprint* BP = TargetWidget->GetTypedOuter<UWidgetBlueprint>();
|
||||||
|
if (!BP)
|
||||||
|
{
|
||||||
|
UWingServer::Printf(TEXT("ERROR: Could not find owning WidgetBlueprint\n"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
UWidgetTree* Tree = BP->WidgetTree;
|
||||||
|
|
||||||
|
// If it's a panel, make sure it has no children.
|
||||||
|
if (UPanelWidget* Panel = Cast<UPanelWidget>(TargetWidget))
|
||||||
|
{
|
||||||
|
if (Panel->GetChildrenCount() > 0)
|
||||||
|
{
|
||||||
|
UWingServer::Printf(TEXT("ERROR: Widget '%s' has %d children. Remove them first.\n"),
|
||||||
|
*WingUtils::FormatName(TargetWidget), Panel->GetChildrenCount());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FString WidgetName = WingUtils::FormatName(TargetWidget);
|
||||||
|
|
||||||
|
// Remove delegate bindings that reference this widget.
|
||||||
|
FString WidgetObjName = TargetWidget->GetName();
|
||||||
|
for (int32 i = BP->Bindings.Num() - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
if (BP->Bindings[i].ObjectName == WidgetObjName)
|
||||||
|
BP->Bindings.RemoveAt(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove the widget from the tree.
|
||||||
|
Tree->RemoveWidget(TargetWidget);
|
||||||
|
|
||||||
|
// Remove variable nodes from the blueprint graph if this was a variable.
|
||||||
|
if (TargetWidget->bIsVariable)
|
||||||
|
{
|
||||||
|
FBlueprintEditorUtils::RemoveVariableNodes(BP, TargetWidget->GetFName());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rename to transient package to avoid name conflicts with future widgets.
|
||||||
|
TargetWidget->Rename(nullptr, GetTransientPackage());
|
||||||
|
|
||||||
|
UWingServer::Printf(TEXT("Deleted widget '%s'\n"), *WidgetName);
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "CoreMinimal.h"
|
||||||
|
#include "WingServer.h"
|
||||||
|
#include "WingHandler.h"
|
||||||
|
#include "WingFetcher.h"
|
||||||
|
#include "WingUtils.h"
|
||||||
|
#include "WingWidgets.h"
|
||||||
|
#include "WidgetBlueprint.h"
|
||||||
|
#include "Blueprint/WidgetTree.h"
|
||||||
|
#include "Components/PanelWidget.h"
|
||||||
|
#include "Widget_Reparent.generated.h"
|
||||||
|
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
UCLASS()
|
||||||
|
class UWing_Widget_Reparent : public UObject, public IWingHandler
|
||||||
|
{
|
||||||
|
GENERATED_BODY()
|
||||||
|
|
||||||
|
public:
|
||||||
|
UPROPERTY(meta=(Description="Path to the widget, eg /Game/Widgets/WB_Test,widget:MyButton"))
|
||||||
|
FString Widget;
|
||||||
|
|
||||||
|
UPROPERTY(meta=(Description="Name of the new parent widget. Must be a panel."))
|
||||||
|
FString Parent;
|
||||||
|
|
||||||
|
virtual FString GetDescription() const override
|
||||||
|
{
|
||||||
|
return TEXT("Move a widget to a different parent in a Widget Blueprint's widget tree.");
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void Handle() override
|
||||||
|
{
|
||||||
|
// Walk to the widget.
|
||||||
|
WingFetcher F;
|
||||||
|
UWidget* TargetWidget = F.Walk(Widget).Cast<UWidget>();
|
||||||
|
if (!TargetWidget) return;
|
||||||
|
|
||||||
|
// Get the widget blueprint from the widget's outer chain.
|
||||||
|
UWidgetBlueprint* BP = TargetWidget->GetTypedOuter<UWidgetBlueprint>();
|
||||||
|
if (!BP)
|
||||||
|
{
|
||||||
|
UWingServer::Printf(TEXT("ERROR: Could not find owning WidgetBlueprint\n"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
UWidgetTree* Tree = BP->WidgetTree;
|
||||||
|
|
||||||
|
// Get all widgets for name lookup.
|
||||||
|
TArray<UWidget*> AllWidgets;
|
||||||
|
Tree->GetAllWidgets(AllWidgets);
|
||||||
|
|
||||||
|
FString WidgetName = WingUtils::FormatName(TargetWidget);
|
||||||
|
|
||||||
|
// Find the new parent and verify it's a panel with room.
|
||||||
|
UWidget* ParentWidget = WingUtils::FindExactlyOneNamed(Parent, AllWidgets, TEXT("Widget"));
|
||||||
|
if (!ParentWidget) return;
|
||||||
|
if (!WingWidgets::CheckCanBeParent(ParentWidget)) return;
|
||||||
|
UPanelWidget* ParentPanel = Cast<UPanelWidget>(ParentWidget);
|
||||||
|
|
||||||
|
// Check for circular reparenting.
|
||||||
|
for (UPanelWidget* Ancestor = ParentPanel; Ancestor != nullptr; Ancestor = Ancestor->GetParent())
|
||||||
|
{
|
||||||
|
if (Ancestor == TargetWidget)
|
||||||
|
{
|
||||||
|
UWingServer::Printf(TEXT("ERROR: Cannot reparent '%s' under itself\n"), *WidgetName);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove from current location.
|
||||||
|
Tree->RemoveWidget(TargetWidget);
|
||||||
|
|
||||||
|
// Add to new parent.
|
||||||
|
ParentPanel->AddChild(TargetWidget);
|
||||||
|
|
||||||
|
UWingServer::Printf(TEXT("Reparented '%s' under '%s'\n"), *WidgetName, *Parent);
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -90,6 +90,22 @@ TArray<WingWidgets::Type> WingWidgets::Search(const FString& Query, int32 MaxRes
|
|||||||
return Results;
|
return Results;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool WingWidgets::CheckCanBeParent(UWidget* Widget)
|
||||||
|
{
|
||||||
|
UPanelWidget* Panel = Cast<UPanelWidget>(Widget);
|
||||||
|
if (!Panel)
|
||||||
|
{
|
||||||
|
UWingServer::Printf(TEXT("ERROR: '%s' is not a panel widget and cannot have children\n"), *WingUtils::FormatName(Widget));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!Panel->CanAddMoreChildren())
|
||||||
|
{
|
||||||
|
UWingServer::Printf(TEXT("ERROR: '%s' already has a child and cannot accept more\n"), *WingUtils::FormatName(Widget));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void WingWidgets::PrintWidgetTree(UWidget* Widget, int32 Depth)
|
void WingWidgets::PrintWidgetTree(UWidget* Widget, int32 Depth)
|
||||||
{
|
{
|
||||||
FString Indent = FString::ChrN(Depth * 2, TEXT(' '));
|
FString Indent = FString::ChrN(Depth * 2, TEXT(' '));
|
||||||
|
|||||||
@@ -24,6 +24,9 @@ public:
|
|||||||
// Search for widget types whose name matches the query.
|
// Search for widget types whose name matches the query.
|
||||||
TArray<Type> Search(const FString& Query, int32 MaxResults, bool Exact);
|
TArray<Type> Search(const FString& Query, int32 MaxResults, bool Exact);
|
||||||
|
|
||||||
|
// Check if a widget can accept children. Prints error if not.
|
||||||
|
static bool CheckCanBeParent(UWidget* Widget);
|
||||||
|
|
||||||
// Print out a tree of widgets, just showing the names and types.
|
// Print out a tree of widgets, just showing the names and types.
|
||||||
static void PrintWidgetTree(UWidget* Widget, int32 Depth);
|
static void PrintWidgetTree(UWidget* Widget, int32 Depth);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user