Files
integration/Source/Integration/RootCanvas.h
2026-04-22 07:22:55 -04:00

153 lines
5.4 KiB
C++

////////////////////////////////////////////////////////////
//
// 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.
//
////////////////////////////////////////////////////////////
#pragma once
#include "CoreMinimal.h"
#include "Common.h"
#include "Blueprint/UserWidget.h"
#include "Components/CanvasPanel.h"
#include "Components/CanvasPanelSlot.h"
#include "RootCanvas.generated.h"
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
{
GENERATED_BODY()
public:
UlxRootCanvasSlot(const FObjectInitializer& ObjectInitializer);
// When this window is in front, the mouse pointer is shown and the
// viewport does not capture the mouse.
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Luprex|Input Mode")
bool ShowPointer = false;
// When this window is in front, this window's input component blocks
// lower-priority input components in the input stack.
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Luprex|Input Mode")
bool BlockInput = false;
// If true, this widget's input component is enabled, which is to say,
// that enhanced input events are enabled. If false, enhanced input
// events in the Event Graph are deactivated.
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;
// 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();
};
////////////////////////////////////////////////////////////
//
// 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
{
GENERATED_BODY()
public:
// Convenience wrapper around AddChild that returns the
// derived slot type, so callers don't have to cast.
UFUNCTION()
UlxRootCanvasSlot* AddChildToRootCanvas(UWidget* Content);
// Find children of type UserWidget. Return them in a sorted
// order, with the highest Zorder first.
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;
// This function updates several window-management-related properties
// which are stored in the UserWidget and the lxRootCanvasSlot. Note that
// it is perfectly legal to edit these properties by other means: this
// function is one of many valid setters. See the documentation in
// Docs/Keyboard-Focus-and-Input-Modes.md for information about how Luprex
// window management works.
UFUNCTION(BlueprintCallable, Category = "Luprex|Window Management",
meta = (DefaultToSelf = "Widget", EnableEnhancedInput = "true"))
static void SetWidgetWindowManagement(class UUserWidget *Widget,
bool ShowPointer, bool BlockInput, bool EnableEnhancedInput,
bool BringToFront, UWidget *DesiredFocusWidget);
// 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
// UlxRootCanvasSlot).
UFUNCTION(BlueprintCallable, Category = "Luprex|Window Management",
meta = (DefaultToSelf = "Widget", ExpandEnumAsExecs = "Result"))
static UlxRootCanvasSlot *GetRootCanvasSlot(class UUserWidget *Widget, ElxSuccessOrWrongType &Result);
protected:
// UPanelWidget
virtual UClass* GetSlotClass() const override;
};
////////////////////////////////////////////////////////////
//
// UlxRootWidget
//
// A trivial concrete UUserWidget subclass used by the
// PlayerController to host the root UlxRootCanvasPanel.
// UUserWidget itself is marked Abstract in UMG, so we need
// a non-abstract class to instantiate.
//
////////////////////////////////////////////////////////////
UCLASS()
class INTEGRATION_API UlxRootWidget : public UUserWidget
{
GENERATED_BODY()
};