// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "CoreMinimal.h" #include "InputCoreTypes.h" #include "Components/ActorComponent.h" #include "HitProxies.h" #include "ConvexVolume.h" #include "ComponentVisualizer.generated.h" class AActor; class FCanvas; class FEditorViewportClient; class FPrimitiveDrawInterface; class FSceneView; class FViewport; class SWidget; struct FViewportClick; struct HComponentVisProxy: public HHitProxy { DECLARE_HIT_PROXY(UNREALED_API); HComponentVisProxy(const UActorComponent* InComponent, EHitProxyPriority InPriority = HPP_Wireframe) : HHitProxy(InPriority), Component(InComponent) {} virtual EMouseCursor::Type GetMouseCursor() override { return EMouseCursor::Crosshairs; } TWeakObjectPtr Component; }; USTRUCT() struct FPropertyNameAndIndex { public: GENERATED_USTRUCT_BODY() FPropertyNameAndIndex() : Name(NAME_None), Index(INDEX_NONE) {} explicit FPropertyNameAndIndex(FName InName, int32 InIndex = 0) : Name(InName), Index(InIndex) {} bool IsValid() const { return Name != NAME_None && Index != INDEX_NONE; } void Clear() { Name = NAME_None; Index = INDEX_NONE; } bool operator==(const FPropertyNameAndIndex& InRHS) const { return (Name == InRHS.Name && Index == InRHS.Index); } UPROPERTY() FName Name; UPROPERTY() int32 Index; }; /** * Describes a chain of properties from the parent actor of a given component, to the component itself. */ USTRUCT() struct UNREALED_API FComponentPropertyPath { public: GENERATED_USTRUCT_BODY() FComponentPropertyPath() = default; explicit FComponentPropertyPath(const UActorComponent* Component) { Set(Component); } /** Resets the property path */ void Reset() { ParentOwningActor = nullptr; LastResortComponentPtr = nullptr; PropertyChain.Reset(); } /** Gets the parent owning actor for the component, or nullptr if it is not valid */ AActor* GetParentOwningActor() const { return ParentOwningActor.Get(); } /** Gets a pointer to the component, or nullptr if it is not valid */ UActorComponent* GetComponent() const; /** Determines whether the property path is valid or not */ bool IsValid() const; bool operator==(const FComponentPropertyPath& InRHS) const { return (ParentOwningActor == InRHS.ParentOwningActor && LastResortComponentPtr == InRHS.LastResortComponentPtr && PropertyChain == InRHS.PropertyChain); } bool operator!=(const FComponentPropertyPath& InRHS) const { return (ParentOwningActor != InRHS.ParentOwningActor || LastResortComponentPtr != InRHS.LastResortComponentPtr || PropertyChain != InRHS.PropertyChain); } private: /** Sets the component referred to by the object */ void Set(const UActorComponent* Component); UPROPERTY() TWeakObjectPtr ParentOwningActor; UPROPERTY() TWeakObjectPtr LastResortComponentPtr; UPROPERTY() TArray PropertyChain; }; /** Base class for a component visualizer, that draw editor information for a particular component class */ class UNREALED_API FComponentVisualizer: public TSharedFromThis { public: FComponentVisualizer() {} virtual ~FComponentVisualizer() {} /** */ virtual void OnRegister() {} /** Draw visualization for the supplied component */ virtual void DrawVisualization(const UActorComponent* Component, const FSceneView* View, FPrimitiveDrawInterface* PDI) {} /** Draw HUD on viewport for the supplied component */ virtual void DrawVisualizationHUD(const UActorComponent* Component, const FViewport* Viewport, const FSceneView* View, FCanvas* Canvas) {} /** */ virtual bool VisProxyHandleClick(FEditorViewportClient* InViewportClient, HComponentVisProxy* VisProxy, const FViewportClick& Click) { return false; } /** */ virtual void EndEditing() {} /** */ virtual bool GetWidgetLocation(const FEditorViewportClient* ViewportClient, FVector& OutLocation) const { return false; } /** */ virtual bool GetCustomInputCoordinateSystem(const FEditorViewportClient* ViewportClient, FMatrix& OutMatrix) const { return false; } /** */ virtual bool HandleInputDelta(FEditorViewportClient* ViewportClient, FViewport* Viewport, FVector& DeltaTranslate, FRotator& DeltalRotate, FVector& DeltaScale) { return false; } /** */ virtual bool HandleInputKey(FEditorViewportClient* ViewportClient, FViewport* Viewport, FKey Key, EInputEvent Event) { return false; } /** Handle click modified by Alt, Ctrl and/or Shift. The input HitProxy may not be on this component. */ virtual bool HandleModifiedClick(FEditorViewportClient* InViewportClient, HHitProxy* HitProxy, const FViewportClick& Click) { return false; } /** Handle box select input */ virtual bool HandleBoxSelect(const FBox& InBox, FEditorViewportClient* InViewportClient, FViewport* InViewport) { return false; } /** Handle frustum select input */ virtual bool HandleFrustumSelect(const FConvexVolume& InFrustum, FEditorViewportClient* InViewportClient, FViewport* InViewport) { return false; } /** Return whether focus on selection should focus on bounding box defined by active visualizer */ virtual bool HasFocusOnSelectionBoundingBox(FBox& OutBoundingBox) { return false; } /** Pass snap input to active visualizer */ virtual bool HandleSnapTo(const bool bInAlign, const bool bInUseLineTrace, const bool bInUseBounds, const bool bInUsePivot, AActor* InDestination) { return false; } /** Get currently edited component, this is needed to reset the active visualizer after undo/redo */ virtual UActorComponent* GetEditedComponent() const { return nullptr; } /** */ virtual TSharedPtr GenerateContextMenu() const { return TSharedPtr(); } /** */ virtual bool IsVisualizingArchetype() const { return false; } // So deprecated code expecting this as an inner class still works using FPropertyNameAndIndex = ::FPropertyNameAndIndex; /** Find the name of the property that points to this component */ UE_DEPRECATED(4.24, "Please use the FComponentPropertyPath class to build property name paths for components.") static FPropertyNameAndIndex GetComponentPropertyName(const UActorComponent* Component); /** Get a component pointer from the property name */ UE_DEPRECATED(4.24, "Please use the FComponentPropertyPath::GetComponent() to retrieve a component pointer from a property name path.") static UActorComponent* GetComponentFromPropertyName(const AActor* CompOwner, const FPropertyNameAndIndex& Property); /** Notify that a component property has been modified */ static void NotifyPropertyModified(UActorComponent* Component, FProperty* Property, EPropertyChangeType::Type PropertyChangeType = EPropertyChangeType::Unspecified); /** Notify that many component properties have been modified */ static void NotifyPropertiesModified(UActorComponent* Component, const TArray& Properties, EPropertyChangeType::Type PropertyChangeType = EPropertyChangeType::Unspecified); }; struct FCachedComponentVisualizer { FComponentPropertyPath ComponentPropertyPath; TSharedPtr Visualizer; FCachedComponentVisualizer(UActorComponent* InComponent, TSharedPtr& InVisualizer) : ComponentPropertyPath(InComponent), Visualizer(InVisualizer) {} };