// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "Templates/SharedPointerFwd.h" #include "SOverrideStatusWidget.h" class FPropertyPath; struct FOverrideStatusSubject; DECLARE_DELEGATE_RetVal_OneParam(bool, FOverrideStatus_CanCreateWidget, const FOverrideStatusSubject&); DECLARE_DELEGATE_RetVal_OneParam(EOverrideWidgetStatus::Type, FOverrideStatus_GetStatus, const FOverrideStatusSubject&); DECLARE_DELEGATE_RetVal_TwoParams(FReply, FOverrideStatus_OnWidgetClicked, const FOverrideStatusSubject&, EOverrideWidgetStatus::Type); DECLARE_DELEGATE_RetVal_TwoParams(TSharedRef, FOverrideStatus_OnGetMenuContent, const FOverrideStatusSubject&, EOverrideWidgetStatus::Type); DECLARE_DELEGATE_RetVal_OneParam(FReply, FOverrideStatus_AddOverride, const FOverrideStatusSubject&); DECLARE_DELEGATE_RetVal_OneParam(FReply, FOverrideStatus_ClearOverride, const FOverrideStatusSubject&); DECLARE_DELEGATE_RetVal_OneParam(FReply, FOverrideStatus_ResetToDefault, const FOverrideStatusSubject&); DECLARE_DELEGATE_RetVal_OneParam(bool, FOverrideStatus_ValueDiffersFromDefault, const FOverrideStatusSubject&); /** * A template handle pointing to given object type */ template struct FOverrideStatusObjectHandle { public: FOverrideStatusObjectHandle() : Object(nullptr) , Key(NAME_None) { } FOverrideStatusObjectHandle(const T* InObject, const FName& InKey = NAME_None) : Object(InObject) , Key(InKey) { } bool IsValid() const { return Object != nullptr; } operator bool() const { return IsValid(); } const T* GetObject() const { return Object; } const FName& GetKey() const { return Key; } bool operator==(const FOverrideStatusObjectHandle& InOther) const { return (Object == InOther.Object) && (Key == InOther.Key); } const T* operator->() const { return GetObject(); } private: const T* Object; FName Key; }; /** * A single object used within an override widget - the object is identified by a weak object pointer and a potential sub object key. */ struct ANIMATIONEDITORWIDGETS_API FOverrideStatusObject { public: FOverrideStatusObject(); FOverrideStatusObject(const UObject* InObject, const FName& InKey = NAME_None); FName GetFName() const; bool IsValid() const; const UObject* GetObject() const; const FName& GetKey() const; bool operator==(const FOverrideStatusObject& InOther) const; template FOverrideStatusObjectHandle GetHandle() const { return FOverrideStatusObjectHandle(Cast(GetObject()), GetKey()); } private: TWeakObjectPtr WeakObjectPtr; FName Key; }; /** * The subject of an override status (widget). * To support multi selection the subject is represented by an array of objects and a property path. * This class also offers helper template functions to facilitate the interaction between the list * of subject object and the user interface layer. */ struct ANIMATIONEDITORWIDGETS_API FOverrideStatusSubject { public: FOverrideStatusSubject(const TArray& InObjects, const TSharedPtr& InPropertyPath, const FName& InCategory); FOverrideStatusSubject(const FOverrideStatusObject& InObject, const TSharedPtr& InPropertyPath = nullptr, const FName& InCategory = NAME_None); FOverrideStatusSubject(const UObject* InObject, const TSharedPtr& InPropertyPath = nullptr, const FName& InCategory = NAME_None, const FName& InKey = NAME_None); // returns true if any of the objects within the subject is still valid bool IsValid() const; // returns the number of objects int32 Num() const; // array access operator const FOverrideStatusObject& operator [](int32 InIndex) const; // array handle access template FOverrideStatusObjectHandle GetHandle(int32 InIndex) const { return operator[](InIndex).GetHandle(); } // range access TArray::RangedForConstIteratorType begin() const { return Objects.begin(); } TArray::RangedForConstIteratorType end() const { return Objects.end(); } // returns true if this subject contains a property path bool HasPropertyPath() const; // getter for the property path const TSharedPtr& GetPropertyPath() const; // getter for the propery path string (uses a cache inside and is faster than GetPropertyPath()->ToString()) const FString& GetPropertyPathString(const TCHAR* Separator = TEXT("->")) const; // returns true if this subject is linked to a category bool HasCategory() const; // getter for category const FName& GetCategory() const; // returns true if a given object is part of the subject bool Contains(const FOverrideStatusObject& InObject) const; // returns true if the subject contains an object of type ObjectType template bool Contains() const { for(int32 Index = 0; Index < Num(); Index++) { if(Cast(operator[](Index).GetObject())) { return true; } } return false; } // returns true if the subject contains an object matching the given predicate template bool Contains(TFunction&)> InMatchPredicate) const { for(int32 Index = 0; Index < Num(); Index++) { if(const FOverrideStatusObjectHandle Handle = GetHandle(Index)) { if(InMatchPredicate(Handle)) { return true; } } } return false; } // returns the index of a given object or INDEX_NONE int32 Find(const FOverrideStatusObject& InObject) const; // returns the index of a given object or INDEX_NONE, // the match is determined based on the given predicate template int32 Find(TFunction&)> InMatchPredicate) const { for(int32 Index = 0; Index < Num(); Index++) { if(const FOverrideStatusObjectHandle Handle = GetHandle(Index)) { if(InMatchPredicate(Handle)) { return true; } } } return false; } // executes a given predicate for each object in the subject template void ForEach(TFunction&)> InPerObjectPredicate) const { for(int32 Index = 0; Index < Num(); Index++) { if(const FOverrideStatusObjectHandle Handle = GetHandle(Index)) { InPerObjectPredicate(Handle); } } } // returns the first valid value for a given predicate (or an unset TOptional). each object in the subject // is interrogated for using the predicate and can return a TOptional indicating success. template TOptional GetFirstValue(TFunction(const FOverrideStatusObjectHandle&)> InGetValuePerObjectPredicate) const { for(int32 Index = 0; Index < Num(); Index++) { if(const FOverrideStatusObjectHandle Handle = GetHandle(Index)) { const TOptional SingleValue = InGetValuePerObjectPredicate(Handle); if(SingleValue.IsSet()) { return SingleValue; } } } return TOptional(); } // returns a common for a given predicate (or an unset TOptional). each object in the subject // is interrogated for using the predicate and can return a TOptional indicating success. // if the value matches for all objects the value will be returned as a set TOptional, otherwise // an unset TOptional will be returned. template TOptional GetCommonValue(TFunction(const FOverrideStatusObjectHandle&)> InGetValuePerObjectPredicate) const { TOptional Result; for(int32 Index = 0; Index < Num(); Index++) { if(const FOverrideStatusObjectHandle Handle = GetHandle(Index)) { const TOptional SingleValue = InGetValuePerObjectPredicate(Handle); if(SingleValue.IsSet()) { if(Result.IsSet()) { if(Result.GetValue() != SingleValue) { Result.Reset(); break; } } else { Result = SingleValue; } } } } return Result; } // returns the status provided by the subject's objects or an empty TOptional if it varies across objects template TOptional GetStatus(TFunction(const FOverrideStatusObjectHandle&)> InGetValuePerObjectPredicate) const { return GetCommonValue(InGetValuePerObjectPredicate); } private: TArray Objects; TSharedPtr PropertyPath; FName SubObjectKey; FName Category; mutable TOptional LastSeparator; mutable TOptional LastPropertyPathString; };