163 lines
5.8 KiB
C++
163 lines
5.8 KiB
C++
////////////////////////////////////////////////////////////
|
|
//
|
|
// RootCanvas.h
|
|
//
|
|
// 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
|
|
//
|
|
////////////////////////////////////////////////////////////
|
|
|
|
#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
|
|
//
|
|
////////////////////////////////////////////////////////////
|
|
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;
|
|
|
|
// Sequence number assigned when this slot was last brought to front.
|
|
int32 BringToFrontCount = 0;
|
|
|
|
// 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
|
|
//
|
|
////////////////////////////////////////////////////////////
|
|
UCLASS()
|
|
class INTEGRATION_API UlxRootCanvasPanel : public UCanvasPanel
|
|
{
|
|
GENERATED_BODY()
|
|
|
|
public:
|
|
|
|
// 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 bottom window first and the top window last.
|
|
TArray<UlxRootCanvasSlot*> GetSortedUserWidgets();
|
|
|
|
// 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
|
|
// 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);
|
|
|
|
// 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
|
|
// UlxRootCanvasSlot).
|
|
UFUNCTION(BlueprintCallable, Category = "Luprex|Window Management",
|
|
meta = (DefaultToSelf = "Widget", ExpandEnumAsExecs = "Result"))
|
|
static UlxRootCanvasSlot *GetRootCanvasSlot(class UUserWidget *Widget, ElxSuccessOrWrongType &Result);
|
|
|
|
protected:
|
|
|
|
// 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;
|
|
};
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////
|
|
//
|
|
// 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()
|
|
};
|