Fix some issues with new root canvas stuff
This commit is contained in:
Binary file not shown.
@@ -163,8 +163,7 @@ void AlxPlayerControllerBase::AddWidgetToRoot(UUserWidget *Widget)
|
||||
|
||||
if (Widget->GetParent() == PC->RootCanvas) return;
|
||||
|
||||
UlxRootCanvasSlot *Slot = PC->RootCanvas->AddChildToRootCanvas(Widget);
|
||||
Slot->SlotUnderConstruction = false;
|
||||
PC->RootCanvas->AddChildToRootCanvas(Widget);
|
||||
}
|
||||
|
||||
void AlxPlayerControllerBase::BuildInputStack(TArray<UInputComponent*>& InputStack)
|
||||
@@ -239,7 +238,7 @@ void AlxPlayerControllerBase::BuildInputStack(TArray<UInputComponent*>& InputSta
|
||||
}
|
||||
|
||||
// Now add the widget-managed input components.
|
||||
for (UlxRootCanvasSlot *Slot : ReverseIterate(WidgetSlots))
|
||||
for (UlxRootCanvasSlot *Slot : WidgetSlots)
|
||||
{
|
||||
if (Slot->EnableEnhancedInput)
|
||||
{
|
||||
@@ -269,15 +268,14 @@ void AlxPlayerControllerBase::UpdateInputMode()
|
||||
if (!SlateUser.IsValid()) return;
|
||||
|
||||
|
||||
// Get the desired configuration from the first widget.
|
||||
// TODO: Maybe we don't have to sort the whole array.
|
||||
TArray<UlxRootCanvasSlot*> WidgetSlots = RootCanvas->GetSortedUserWidgets();
|
||||
RootCanvas->UpdateZOrders();
|
||||
|
||||
// Get the desired configuration from the top widget.
|
||||
UUserWidget *Widget = nullptr;
|
||||
UWidget *Focus = nullptr;
|
||||
bool ShowPointer = false;
|
||||
if (!WidgetSlots.IsEmpty())
|
||||
if (UlxRootCanvasSlot *Top = RootCanvas->GetTopWidget())
|
||||
{
|
||||
UlxRootCanvasSlot *Top = WidgetSlots[0];
|
||||
Widget = Cast<UUserWidget>(Top->GetContent());
|
||||
Focus = Widget->GetDesiredFocusWidget();
|
||||
ShowPointer = Top->ShowPointer;
|
||||
|
||||
@@ -18,33 +18,6 @@ UlxRootCanvasSlot::UlxRootCanvasSlot(const FObjectInitializer& ObjectInitializer
|
||||
SetOffsets(FMargin(0.0f, 0.0f, 0.0f, 0.0f));
|
||||
}
|
||||
|
||||
void UlxRootCanvasSlot::SetZOrderReliable(int32 Order)
|
||||
{
|
||||
if (SlotUnderConstruction)
|
||||
{
|
||||
PRAGMA_DISABLE_DEPRECATION_WARNINGS
|
||||
ZOrder = Order;
|
||||
PRAGMA_ENABLE_DEPRECATION_WARNINGS
|
||||
}
|
||||
else
|
||||
{
|
||||
SetZOrder(Order);
|
||||
}
|
||||
}
|
||||
|
||||
int32 UlxRootCanvasSlot::GetZOrderReliable()
|
||||
{
|
||||
if (SlotUnderConstruction)
|
||||
{
|
||||
PRAGMA_DISABLE_DEPRECATION_WARNINGS
|
||||
return ZOrder;
|
||||
PRAGMA_ENABLE_DEPRECATION_WARNINGS
|
||||
}
|
||||
else
|
||||
{
|
||||
return GetZOrder();
|
||||
}
|
||||
}
|
||||
|
||||
UClass* UlxRootCanvasPanel::GetSlotClass() const
|
||||
{
|
||||
@@ -70,16 +43,24 @@ UlxRootCanvasSlot* UlxRootCanvasPanel::AddChildToRootCanvas(UWidget* Content)
|
||||
return Cast<UlxRootCanvasSlot>(Super::AddChild(Content));
|
||||
}
|
||||
|
||||
int32 UlxRootCanvasPanel::GetMaxZOrder() const
|
||||
void UlxRootCanvasPanel::OnSlotAdded(UPanelSlot* InSlot)
|
||||
{
|
||||
int32 MaxZOrder = 0;
|
||||
for (UPanelSlot *PanelSlot : Slots)
|
||||
UlxRootCanvasSlot *Slot = CastChecked<UlxRootCanvasSlot>(InSlot);
|
||||
Slot->BringToFrontCount = ++BringToFrontCounter;
|
||||
Super::OnSlotAdded(InSlot);
|
||||
}
|
||||
|
||||
|
||||
UlxRootCanvasSlot* UlxRootCanvasPanel::GetTopWidget()
|
||||
{
|
||||
UlxRootCanvasSlot* Top = nullptr;
|
||||
for (UPanelSlot* PanelSlot : Slots)
|
||||
{
|
||||
UlxRootCanvasSlot *TypedSlot = Cast<UlxRootCanvasSlot>(PanelSlot);
|
||||
check(TypedSlot);
|
||||
MaxZOrder = FMath::Max(MaxZOrder, TypedSlot->GetZOrderReliable());
|
||||
UlxRootCanvasSlot* Slot = CastChecked<UlxRootCanvasSlot>(PanelSlot);
|
||||
if (Cast<UUserWidget>(Slot->Content) == nullptr) continue;
|
||||
if ((Top == nullptr) || (*Top < *Slot)) Top = Slot;
|
||||
}
|
||||
return MaxZOrder;
|
||||
return Top;
|
||||
}
|
||||
|
||||
TArray<UlxRootCanvasSlot*> UlxRootCanvasPanel::GetSortedUserWidgets()
|
||||
@@ -95,12 +76,33 @@ TArray<UlxRootCanvasSlot*> UlxRootCanvasPanel::GetSortedUserWidgets()
|
||||
}
|
||||
Result.StableSort([](const UlxRootCanvasSlot &A, const UlxRootCanvasSlot &B)
|
||||
{
|
||||
return A.GetZOrder() > B.GetZOrder();
|
||||
return A < B;
|
||||
});
|
||||
return Result;
|
||||
}
|
||||
|
||||
|
||||
void UlxRootCanvasPanel::UpdateZOrders()
|
||||
{
|
||||
for (UPanelSlot *PanelSlot : Slots)
|
||||
{
|
||||
UlxRootCanvasSlot *Slot = Cast<UlxRootCanvasSlot>(PanelSlot);
|
||||
check(Slot);
|
||||
int32 ZOrder = (Slot->ShowPointer ? 1000000 : 0) + Slot->BringToFrontCount;
|
||||
Slot->SetZOrder(ZOrder);
|
||||
}
|
||||
}
|
||||
|
||||
void UlxRootCanvasPanel::BringToFront(UUserWidget *Widget)
|
||||
{
|
||||
if (!IsValid(Widget)) return;
|
||||
UlxRootCanvasSlot *Slot = Cast<UlxRootCanvasSlot>(Widget->Slot);
|
||||
if (!Slot) return;
|
||||
UlxRootCanvasPanel *Panel = Cast<UlxRootCanvasPanel>(Slot->Parent);
|
||||
if (!Panel) return;
|
||||
Slot->BringToFrontCount = ++Panel->BringToFrontCounter;
|
||||
}
|
||||
|
||||
void UlxRootCanvasPanel::SetWidgetWindowManagement(class UUserWidget *Widget,
|
||||
bool ShowPointer, bool BlockInput, bool EnableEnhancedInput, bool BringToFront, UWidget *DesiredFocusWidget)
|
||||
{
|
||||
@@ -120,7 +122,15 @@ void UlxRootCanvasPanel::SetWidgetWindowManagement(class UUserWidget *Widget,
|
||||
Slot->ShowPointer = ShowPointer;
|
||||
Slot->BlockInput = BlockInput;
|
||||
Slot->EnableEnhancedInput = EnableEnhancedInput;
|
||||
Widget->SetDesiredFocusWidget(DesiredFocusWidget);
|
||||
if (BringToFront) Slot->SetZOrderReliable(Panel->GetMaxZOrder() + 1);
|
||||
if (DesiredFocusWidget)
|
||||
{
|
||||
if (!Widget->SetDesiredFocusWidget(DesiredFocusWidget))
|
||||
UE_LOG(LogLuprexIntegration, Error, TEXT("SetWidgetWindowManagement: focus widget must be a child of widget"));
|
||||
}
|
||||
else
|
||||
{
|
||||
Widget->SetDesiredFocusWidget(NAME_None);
|
||||
}
|
||||
if (BringToFront) Slot->BringToFrontCount = ++Panel->BringToFrontCounter;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,13 +2,16 @@
|
||||
//
|
||||
// RootCanvas.h
|
||||
//
|
||||
// UlxRootCanvasPanel is a UCanvasPanel subclass whose
|
||||
// slots (UlxRootCanvasSlot) carry input-mode configuration
|
||||
// in addition to layout. The PlayerController scans these
|
||||
// slots, sorted by ZOrder, to arbitrate pointer visibility,
|
||||
// capture, focus, and input-component blocking for
|
||||
// top-level widgets. ZOrder therefore serves double duty:
|
||||
// it determines draw order AND input priority.
|
||||
// Luprex provides a "window management system" for root
|
||||
// widgets. In this system, all top-level widgets have to go
|
||||
// into the root canvas (instead of the viewport). The
|
||||
// window management system monitors the widgets within the
|
||||
// root canvas and continuously updates the z-orders, the
|
||||
// pointer visibility, the mouse capture mode, the keyboard
|
||||
// focus, and enhanced input event routing based on hints
|
||||
// and directives given by the widgets.
|
||||
//
|
||||
// To learn more, read Docs/Luprex-Window-Management.md
|
||||
//
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -29,11 +32,6 @@ class UWidget;
|
||||
//
|
||||
// UlxRootCanvasSlot
|
||||
//
|
||||
// Luprex provides a "window management system" for root widgets.
|
||||
// This system is documented in Docs/Keyboard-Focus-and-Input-Modes.md
|
||||
// The Root Canvas Slot is how widgets ask the window management system
|
||||
// to engage certain behaviors.
|
||||
//
|
||||
////////////////////////////////////////////////////////////
|
||||
UCLASS()
|
||||
class INTEGRATION_API UlxRootCanvasSlot : public UCanvasPanelSlot
|
||||
@@ -60,32 +58,24 @@ public:
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Luprex|Input Mode")
|
||||
bool EnableEnhancedInput = true;
|
||||
|
||||
// Knowing whether the slot is under construction helps us to work
|
||||
// around some bugs in Unreal. See below.
|
||||
bool SlotUnderConstruction = true;
|
||||
// Sequence number assigned when this slot was last brought to front.
|
||||
int32 BringToFrontCount = 0;
|
||||
|
||||
// Reliable version of SetZOrder. There is a bug in the normal version of
|
||||
// SetZOrder: it crashes if you use it during OnConstruct. We have a
|
||||
// workaround, but it requires using a different getter and setter.
|
||||
UFUNCTION(BlueprintCallable, Category = "Luprex|Input Mode")
|
||||
void SetZOrderReliable(int32 Order);
|
||||
|
||||
// Reliable version of GetZOrder. There is a bug in the normal version of
|
||||
// SetZOrder: it crashes if you use it during OnConstruct. We have a
|
||||
// workaround, but it requires using a different getter and setter.
|
||||
UFUNCTION(BlueprintCallable, Category = "Luprex|Input Mode")
|
||||
int32 GetZOrderReliable();
|
||||
// Widget Z Ordering: widgets that show the pointer go on top of windows
|
||||
// that don't, and within a group, widgets that have greater BringToFrontCount
|
||||
// go on top. Sorting an array with this puts the top windows at the end
|
||||
// of the array.
|
||||
bool operator<(const UlxRootCanvasSlot &Other) const
|
||||
{
|
||||
if (ShowPointer != Other.ShowPointer) return !ShowPointer;
|
||||
return BringToFrontCount < Other.BringToFrontCount;
|
||||
}
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//
|
||||
// UlxRootCanvasPanel
|
||||
//
|
||||
// A UCanvasPanel that uses UlxRootCanvasSlot for its
|
||||
// children instead of the plain UCanvasPanelSlot. Layout
|
||||
// behavior is identical to UCanvasPanel; only the slot
|
||||
// type differs.
|
||||
//
|
||||
////////////////////////////////////////////////////////////
|
||||
UCLASS()
|
||||
class INTEGRATION_API UlxRootCanvasPanel : public UCanvasPanel
|
||||
@@ -94,18 +84,18 @@ class INTEGRATION_API UlxRootCanvasPanel : public UCanvasPanel
|
||||
|
||||
public:
|
||||
|
||||
// Convenience wrapper around AddChild that returns the
|
||||
// derived slot type, so callers don't have to cast.
|
||||
// Add a child to the canvas. Also brings the child to the front
|
||||
// for the first time, ensuring that every widget has a unique
|
||||
// BringToFront counter.
|
||||
UFUNCTION()
|
||||
UlxRootCanvasSlot* AddChildToRootCanvas(UWidget* Content);
|
||||
|
||||
// Find children of type UserWidget. Return them in a sorted
|
||||
// order, with the highest Zorder first.
|
||||
// order, with the bottom window first and the top window last.
|
||||
TArray<UlxRootCanvasSlot*> GetSortedUserWidgets();
|
||||
|
||||
// Return the largest ZOrder across all slots, or 0 if empty.
|
||||
// Used as the basis for placing new widgets on top.
|
||||
int32 GetMaxZOrder() const;
|
||||
// Return the highest-priority UserWidget slot, or nullptr if there are none.
|
||||
UlxRootCanvasSlot* GetTopWidget();
|
||||
|
||||
// This function updates several window-management-related properties
|
||||
// which are stored in the UserWidget and the lxRootCanvasSlot. Note that
|
||||
@@ -119,6 +109,17 @@ public:
|
||||
bool ShowPointer, bool BlockInput, bool EnableEnhancedInput,
|
||||
bool BringToFront, UWidget *DesiredFocusWidget);
|
||||
|
||||
// Bring the widget to the front of the Z order within its group.
|
||||
// This is implemented using the BringToFront counter.
|
||||
UFUNCTION(BlueprintCallable, Category = "Luprex|Window Management",
|
||||
meta = (DefaultToSelf = "Widget"))
|
||||
static void BringToFront(class UUserWidget *Widget);
|
||||
|
||||
// Recompute and apply ZOrder values for all slots based on ShowPointer and
|
||||
// BringToFrontCount. Must be called from a context where SetZOrder is safe -
|
||||
// i.e. not during OnConstruct.
|
||||
void UpdateZOrders();
|
||||
|
||||
// Fetch the UlxRootCanvasSlot for a widget that is parented to a
|
||||
// UlxRootCanvasPanel. Returns nullptr via the WrongType exec pin
|
||||
// if the widget isn't a root widget (no slot, or slot is not a
|
||||
@@ -129,8 +130,17 @@ public:
|
||||
|
||||
protected:
|
||||
|
||||
// UPanelWidget
|
||||
// We inherit most of our code from CanvasPanel. This causes the
|
||||
// CanvasPanel code to allocate slots of type UlxRootCanvasSlot.
|
||||
virtual UClass* GetSlotClass() const override;
|
||||
|
||||
// We override OnSlotAdded in order to be able to be able to
|
||||
// fully finish initializing the slot before the widget
|
||||
// OnConstruct method has a chance to execute.
|
||||
virtual void OnSlotAdded(UPanelSlot* InSlot) override;
|
||||
|
||||
// Monotonic counter incremented each time any slot is brought to front.
|
||||
int32 BringToFrontCounter = 0;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -16,26 +16,32 @@ _FUObjectItemType = None
|
||||
_GNameBlocksDebug = None
|
||||
_GObjectArrayForDebugVisualizers = None
|
||||
|
||||
def _init_globals(target):
|
||||
def _init_globals(frame, bp_loc, dict):
|
||||
global _FNameEntryType, _FNameEntryStride, _FUObjectItemType
|
||||
global _GNameBlocksDebug, _GObjectArrayForDebugVisualizers
|
||||
|
||||
_FNameEntryType = target.FindFirstType('FNameEntry')
|
||||
if not _FNameEntryType.IsValid():
|
||||
print('UEDataFormatter: FNameEntry type not found')
|
||||
_FNameEntryStride = _FNameEntryType.GetByteAlign()
|
||||
target = frame.GetThread().GetProcess().GetTarget()
|
||||
|
||||
_FUObjectItemType = target.FindFirstType('FUObjectItem')
|
||||
if not _FUObjectItemType.IsValid():
|
||||
print('UEDataFormatter: FUObjectItem type not found')
|
||||
if _FNameEntryType is None:
|
||||
t = target.FindFirstType('FNameEntry')
|
||||
if t.IsValid():
|
||||
_FNameEntryType = t
|
||||
_FNameEntryStride = t.GetByteAlign()
|
||||
|
||||
_GNameBlocksDebug = target.FindFirstGlobalVariable('GNameBlocksDebug')
|
||||
if not _GNameBlocksDebug.IsValid():
|
||||
print('UEDataFormatter: GNameBlocksDebug not found')
|
||||
if _FUObjectItemType is None:
|
||||
t = target.FindFirstType('FUObjectItem')
|
||||
if t.IsValid():
|
||||
_FUObjectItemType = t
|
||||
|
||||
_GObjectArrayForDebugVisualizers = target.FindFirstGlobalVariable('GObjectArrayForDebugVisualizers')
|
||||
if not _GObjectArrayForDebugVisualizers.IsValid():
|
||||
print('UEDataFormatter: GObjectArrayForDebugVisualizers not found')
|
||||
if _GNameBlocksDebug is None:
|
||||
v = target.FindFirstGlobalVariable('GNameBlocksDebug')
|
||||
if v.IsValid():
|
||||
_GNameBlocksDebug = v
|
||||
|
||||
if _GObjectArrayForDebugVisualizers is None:
|
||||
v = target.FindFirstGlobalVariable('GObjectArrayForDebugVisualizers')
|
||||
if v.IsValid():
|
||||
_GObjectArrayForDebugVisualizers = v
|
||||
|
||||
|
||||
############################################################
|
||||
@@ -677,8 +683,11 @@ def _register_provider(cat, pattern, summary_fn=None, synth_cls=None):
|
||||
|
||||
def __lldb_init_module(debugger, dict):
|
||||
print("Running lldb_init_module")
|
||||
_init_globals(debugger.GetSelectedTarget())
|
||||
debugger.HandleCommand('target stop-hook add --python-function ' + __name__ + '._init_globals')
|
||||
debugger.HandleCommand('type category delete ' + __name__)
|
||||
frame = debugger.GetSelectedTarget().GetProcess().GetSelectedThread().GetSelectedFrame()
|
||||
if frame.IsValid():
|
||||
_init_globals(frame, None, {})
|
||||
cat = debugger.CreateCategory(__name__)
|
||||
|
||||
_register_provider(cat, '^FString$', summary_fn='UEFStringSummaryProvider')
|
||||
|
||||
Reference in New Issue
Block a user