289 lines
10 KiB
C++
289 lines
10 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#pragma once
|
|
|
|
#include "Containers/Array.h"
|
|
#include "Containers/Map.h"
|
|
#include "CoreTypes.h"
|
|
#include "Delegates/Delegate.h"
|
|
#include "GameplayTagContainer.h"
|
|
#include "Kismet/BlueprintFunctionLibrary.h"
|
|
#include "Subsystems/WorldSubsystem.h"
|
|
#include "Templates/SharedPointer.h"
|
|
#include "Templates/SubclassOf.h"
|
|
#include "Templates/TypeHash.h"
|
|
#include "UObject/Class.h"
|
|
#include "UObject/Object.h"
|
|
#include "UObject/UObjectGlobals.h"
|
|
#include "UObject/WeakObjectPtr.h"
|
|
#include "UObject/WeakObjectPtrTemplates.h"
|
|
|
|
#include "UIExtensionSystem.generated.h"
|
|
|
|
class FSubsystemCollectionBase;
|
|
class UUserWidget;
|
|
struct FFrame;
|
|
|
|
// Match rule for extension points
|
|
UENUM(BlueprintType)
|
|
enum class EUIExtensionPointMatch : uint8
|
|
{
|
|
// An exact match will only receive extensions with exactly the same point
|
|
// (e.g., registering for "A.B" will match a broadcast of A.B but not A.B.C)
|
|
ExactMatch,
|
|
|
|
// A partial match will receive any extensions rooted in the same point
|
|
// (e.g., registering for "A.B" will match a broadcast of A.B as well as A.B.C)
|
|
PartialMatch
|
|
};
|
|
|
|
// Match rule for extension points
|
|
UENUM(BlueprintType)
|
|
enum class EUIExtensionAction : uint8
|
|
{
|
|
Added,
|
|
Removed
|
|
};
|
|
|
|
DECLARE_DELEGATE_TwoParams(FExtendExtensionPointDelegate, EUIExtensionAction Action, const FUIExtensionRequest& Request);
|
|
|
|
/*
|
|
*
|
|
*/
|
|
struct FUIExtension : TSharedFromThis<FUIExtension>
|
|
{
|
|
public:
|
|
/** The extension point this extension is intended for. */
|
|
FGameplayTag ExtensionPointTag;
|
|
int32 Priority = INDEX_NONE;
|
|
TWeakObjectPtr<UObject> ContextObject;
|
|
//Kept alive by UUIExtensionSubsystem::AddReferencedObjects
|
|
UObject* Data = nullptr;
|
|
};
|
|
|
|
/**
|
|
*
|
|
*/
|
|
struct FUIExtensionPoint : TSharedFromThis<FUIExtensionPoint>
|
|
{
|
|
public:
|
|
FGameplayTag ExtensionPointTag;
|
|
TWeakObjectPtr<UObject> ContextObject;
|
|
EUIExtensionPointMatch ExtensionPointTagMatchType = EUIExtensionPointMatch::ExactMatch;
|
|
TArray<UClass*> AllowedDataClasses;
|
|
FExtendExtensionPointDelegate Callback;
|
|
|
|
// Tests if the extension and the extension point match up, if they do then this extension point should learn
|
|
// about this extension.
|
|
bool DoesExtensionPassContract(const FUIExtension* Extension) const;
|
|
};
|
|
|
|
/**
|
|
*
|
|
*/
|
|
USTRUCT(BlueprintType)
|
|
struct UIEXTENSION_API FUIExtensionPointHandle
|
|
{
|
|
GENERATED_BODY()
|
|
|
|
public:
|
|
FUIExtensionPointHandle() {}
|
|
|
|
void Unregister();
|
|
|
|
bool IsValid() const { return DataPtr.IsValid(); }
|
|
|
|
bool operator==(const FUIExtensionPointHandle& Other) const { return DataPtr == Other.DataPtr; }
|
|
bool operator!=(const FUIExtensionPointHandle& Other) const { return !operator==(Other); }
|
|
|
|
friend uint32 GetTypeHash(const FUIExtensionPointHandle& Handle)
|
|
{
|
|
return PointerHash(Handle.DataPtr.Get());
|
|
}
|
|
|
|
private:
|
|
TWeakObjectPtr<UUIExtensionSubsystem> ExtensionSource;
|
|
|
|
TSharedPtr<FUIExtensionPoint> DataPtr;
|
|
|
|
friend UUIExtensionSubsystem;
|
|
|
|
FUIExtensionPointHandle(UUIExtensionSubsystem* InExtensionSource, const TSharedPtr<FUIExtensionPoint>& InDataPtr) : ExtensionSource(InExtensionSource), DataPtr(InDataPtr) {}
|
|
};
|
|
|
|
template<>
|
|
struct TStructOpsTypeTraits<FUIExtensionPointHandle> : public TStructOpsTypeTraitsBase2<FUIExtensionPointHandle>
|
|
{
|
|
enum
|
|
{
|
|
WithCopy = true, // This ensures the opaque type is copied correctly in BPs
|
|
WithIdenticalViaEquality = true,
|
|
};
|
|
};
|
|
|
|
/**
|
|
*
|
|
*/
|
|
USTRUCT(BlueprintType)
|
|
struct UIEXTENSION_API FUIExtensionHandle
|
|
{
|
|
GENERATED_BODY()
|
|
|
|
public:
|
|
FUIExtensionHandle() {}
|
|
|
|
void Unregister();
|
|
|
|
bool IsValid() const { return DataPtr.IsValid(); }
|
|
|
|
bool operator==(const FUIExtensionHandle& Other) const { return DataPtr == Other.DataPtr; }
|
|
bool operator!=(const FUIExtensionHandle& Other) const { return !operator==(Other); }
|
|
|
|
friend FORCEINLINE uint32 GetTypeHash(FUIExtensionHandle Handle)
|
|
{
|
|
return PointerHash(Handle.DataPtr.Get());
|
|
}
|
|
|
|
private:
|
|
TWeakObjectPtr<UUIExtensionSubsystem> ExtensionSource;
|
|
|
|
TSharedPtr<FUIExtension> DataPtr;
|
|
|
|
friend UUIExtensionSubsystem;
|
|
|
|
FUIExtensionHandle(UUIExtensionSubsystem* InExtensionSource, const TSharedPtr<FUIExtension>& InDataPtr) : ExtensionSource(InExtensionSource), DataPtr(InDataPtr) {}
|
|
};
|
|
|
|
template<>
|
|
struct TStructOpsTypeTraits<FUIExtensionHandle> : public TStructOpsTypeTraitsBase2<FUIExtensionHandle>
|
|
{
|
|
enum
|
|
{
|
|
WithCopy = true, // This ensures the opaque type is copied correctly in BPs
|
|
WithIdenticalViaEquality = true,
|
|
};
|
|
};
|
|
|
|
/**
|
|
*
|
|
*/
|
|
USTRUCT(BlueprintType)
|
|
struct FUIExtensionRequest
|
|
{
|
|
GENERATED_BODY()
|
|
|
|
public:
|
|
UPROPERTY(EditAnywhere, BlueprintReadOnly)
|
|
FUIExtensionHandle ExtensionHandle;
|
|
|
|
UPROPERTY(EditAnywhere, BlueprintReadOnly)
|
|
FGameplayTag ExtensionPointTag;
|
|
|
|
UPROPERTY(EditAnywhere, BlueprintReadOnly)
|
|
int32 Priority = INDEX_NONE;
|
|
|
|
UPROPERTY(EditAnywhere, BlueprintReadOnly)
|
|
TObjectPtr<UObject> Data = nullptr;
|
|
|
|
UPROPERTY(EditAnywhere, BlueprintReadOnly)
|
|
TObjectPtr<UObject> ContextObject = nullptr;
|
|
};
|
|
|
|
DECLARE_DYNAMIC_DELEGATE_TwoParams(FExtendExtensionPointDynamicDelegate, EUIExtensionAction, Action, const FUIExtensionRequest&, ExtensionRequest);
|
|
|
|
/**
|
|
*
|
|
*/
|
|
UCLASS()
|
|
class UIEXTENSION_API UUIExtensionSubsystem : public UWorldSubsystem
|
|
{
|
|
GENERATED_BODY()
|
|
|
|
public:
|
|
FUIExtensionPointHandle RegisterExtensionPoint(const FGameplayTag& ExtensionPointTag, EUIExtensionPointMatch ExtensionPointTagMatchType, const TArray<UClass*>& AllowedDataClasses, FExtendExtensionPointDelegate ExtensionCallback);
|
|
FUIExtensionPointHandle RegisterExtensionPointForContext(const FGameplayTag& ExtensionPointTag, UObject* ContextObject, EUIExtensionPointMatch ExtensionPointTagMatchType, const TArray<UClass*>& AllowedDataClasses, FExtendExtensionPointDelegate ExtensionCallback);
|
|
|
|
FUIExtensionHandle RegisterExtensionAsWidget(const FGameplayTag& ExtensionPointTag, TSubclassOf<UUserWidget> WidgetClass, int32 Priority);
|
|
FUIExtensionHandle RegisterExtensionAsWidgetForContext(const FGameplayTag& ExtensionPointTag, UObject* ContextObject, TSubclassOf<UUserWidget> WidgetClass, int32 Priority);
|
|
FUIExtensionHandle RegisterExtensionAsData(const FGameplayTag& ExtensionPointTag, UObject* ContextObject, UObject* Data, int32 Priority);
|
|
|
|
UFUNCTION(BlueprintCallable, BlueprintCosmetic, Category = "UI Extension")
|
|
void UnregisterExtension(const FUIExtensionHandle& ExtensionHandle);
|
|
|
|
UFUNCTION(BlueprintCallable, BlueprintCosmetic, Category = "UI Extension")
|
|
void UnregisterExtensionPoint(const FUIExtensionPointHandle& ExtensionPointHandle);
|
|
|
|
static void AddReferencedObjects(UObject* InThis, FReferenceCollector& Collector);
|
|
|
|
protected:
|
|
virtual void Initialize(FSubsystemCollectionBase& Collection) override;
|
|
virtual void Deinitialize() override;
|
|
|
|
void NotifyExtensionPointOfExtensions(TSharedPtr<FUIExtensionPoint>& ExtensionPoint);
|
|
void NotifyExtensionPointsOfExtension(EUIExtensionAction Action, TSharedPtr<FUIExtension>& Extension);
|
|
|
|
UFUNCTION(BlueprintCallable, BlueprintCosmetic, Category="UI Extension", meta = (DisplayName = "Register Extension Point"))
|
|
FUIExtensionPointHandle K2_RegisterExtensionPoint(FGameplayTag ExtensionPointTag, EUIExtensionPointMatch ExtensionPointTagMatchType, const TArray<UClass*>& AllowedDataClasses, FExtendExtensionPointDynamicDelegate ExtensionCallback);
|
|
|
|
UFUNCTION(BlueprintCallable, BlueprintCosmetic, Category = "UI Extension", meta = (DisplayName = "Register Extension (Widget)"))
|
|
FUIExtensionHandle K2_RegisterExtensionAsWidget(FGameplayTag ExtensionPointTag, TSubclassOf<UUserWidget> WidgetClass, int32 Priority = -1);
|
|
|
|
/**
|
|
* Registers the widget (as data) for a specific player. This means the extension points will receive a UIExtensionForPlayer data object
|
|
* that they can look at to determine if it's for whatever they consider their player.
|
|
*/
|
|
UFUNCTION(BlueprintCallable, BlueprintCosmetic, Category = "UI Extension", meta = (DisplayName = "Register Extension (Widget For Context)"))
|
|
FUIExtensionHandle K2_RegisterExtensionAsWidgetForContext(FGameplayTag ExtensionPointTag, TSubclassOf<UUserWidget> WidgetClass, UObject* ContextObject, int32 Priority = -1);
|
|
|
|
/**
|
|
* Registers the extension as data for any extension point that can make use of it.
|
|
*/
|
|
UFUNCTION(BlueprintCallable, BlueprintCosmetic, Category="UI Extension", meta = (DisplayName = "Register Extension (Data)"))
|
|
FUIExtensionHandle K2_RegisterExtensionAsData(FGameplayTag ExtensionPointTag, UObject* Data, int32 Priority = -1);
|
|
|
|
/**
|
|
* Registers the extension as data for any extension point that can make use of it.
|
|
*/
|
|
UFUNCTION(BlueprintCallable, BlueprintCosmetic, Category="UI Extension", meta = (DisplayName = "Register Extension (Data For Context)"))
|
|
FUIExtensionHandle K2_RegisterExtensionAsDataForContext(FGameplayTag ExtensionPointTag, UObject* ContextObject, UObject* Data, int32 Priority = -1);
|
|
|
|
FUIExtensionRequest CreateExtensionRequest(const TSharedPtr<FUIExtension>& Extension);
|
|
|
|
private:
|
|
typedef TArray<TSharedPtr<FUIExtensionPoint>> FExtensionPointList;
|
|
TMap<FGameplayTag, FExtensionPointList> ExtensionPointMap;
|
|
|
|
typedef TArray<TSharedPtr<FUIExtension>> FExtensionList;
|
|
TMap<FGameplayTag, FExtensionList> ExtensionMap;
|
|
};
|
|
|
|
|
|
UCLASS()
|
|
class UIEXTENSION_API UUIExtensionHandleFunctions : public UBlueprintFunctionLibrary
|
|
{
|
|
GENERATED_BODY()
|
|
|
|
public:
|
|
UUIExtensionHandleFunctions() { }
|
|
|
|
UFUNCTION(BlueprintCallable, BlueprintCosmetic, Category = "UI Extension")
|
|
static void Unregister(UPARAM(ref) FUIExtensionHandle& Handle);
|
|
|
|
UFUNCTION(BlueprintCallable, BlueprintCosmetic, Category = "UI Extension")
|
|
static bool IsValid(UPARAM(ref) FUIExtensionHandle& Handle);
|
|
};
|
|
|
|
UCLASS()
|
|
class UIEXTENSION_API UUIExtensionPointHandleFunctions : public UBlueprintFunctionLibrary
|
|
{
|
|
GENERATED_BODY()
|
|
|
|
public:
|
|
UUIExtensionPointHandleFunctions() { }
|
|
|
|
UFUNCTION(BlueprintCallable, BlueprintCosmetic, Category = "UI Extension")
|
|
static void Unregister(UPARAM(ref) FUIExtensionPointHandle& Handle);
|
|
|
|
UFUNCTION(BlueprintCallable, BlueprintCosmetic, Category = "UI Extension")
|
|
static bool IsValid(UPARAM(ref) FUIExtensionPointHandle& Handle);
|
|
}; |