Last active
April 17, 2025 11:06
-
-
Save jeremyabel/ec86cbaaef594aed2705f5d17e003beb to your computer and use it in GitHub Desktop.
Editable Component Vector Property Visualizer
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Copyright Feral Cat Den, LLC. All Rights Reserved. | |
#include "MyComponentVisualizer.h" | |
#include "ActorEditorUtils.h" | |
#include "EditorViewportClient.h" | |
#include "HitProxies.h" | |
// Include your component here | |
struct HMyPropertyHitProxy : HComponentVisProxy | |
{ | |
DECLARE_HIT_PROXY(); | |
HMyPropertyHitProxy(const UActorComponent* InComponent) | |
: HComponentVisProxy(InComponent, HPP_Wireframe) | |
{} | |
}; | |
IMPLEMENT_HIT_PROXY(HMyPropertyHitProxy, HComponentVisProxy) | |
FMyComponentVisualizer::FMyComponentVisualizer() | |
{ | |
ComponentPath = FComponentPropertyPath(); | |
MyVectorProperty = FindFProperty<FProperty>(UMyComponent::StaticClass(), GET_MEMBER_NAME_CHECKED(UMyComponent, MyVector)); | |
} | |
void FMyComponentVisualizer::DrawVisualization(const UActorComponent* InComponent, const FSceneView* InView, FPrimitiveDrawInterface* InPDI) | |
{ | |
const UMyComponent* EditedComp = Cast<UMyComponent>(InComponent); | |
if (!EditedComp) | |
{ | |
return; | |
} | |
const FVector ProxyHandleLocation = EditedComp->GetComponentTransform().TransformPosition(EditedComp->MyVector); | |
InPDI->SetHitProxy(new HMyPropertyHitProxy(EditedComp)); | |
InPDI->DrawPoint(ProxyHandleLocation, FLinearColor::White, 10.f, SDPG_Foreground); | |
InPDI->SetHitProxy(nullptr); | |
} | |
bool FMyComponentVisualizer::VisProxyHandleClick(FEditorViewportClient* InViewportClient, HComponentVisProxy* VisProxy, const FViewportClick& Click) | |
{ | |
EndEditing(); | |
if (VisProxy && VisProxy->Component.IsValid()) | |
{ | |
if (VisProxy->IsA(HMyPropertyHitProxy::StaticGetType())) | |
{ | |
const UMyComponent* EditedComp = CastChecked<const UMyComponent>(VisProxy->Component.Get()); | |
ComponentPath = FComponentPropertyPath(EditedComp); | |
if (ComponentPath.IsValid()) | |
{ | |
return true; | |
} | |
} | |
} | |
ComponentPath = FComponentPropertyPath(); | |
return false; | |
} | |
UActorComponent* FMyComponentVisualizer::GetEditedComponent() const | |
{ | |
return Cast<UActorComponent>(ComponentPath.GetComponent()); | |
} | |
bool FMyComponentVisualizer::GetWidgetLocation(const FEditorViewportClient* ViewportClient, FVector& OutLocation) const | |
{ | |
if (UMyComponent* EditedComp = Cast<UMyComponent>(GetEditedComponent())) | |
{ | |
OutLocation = EditedComp->GetComponentTransform().TransformPosition(EditedComp->MyVector); | |
return true; | |
} | |
return false; | |
} | |
bool FMyComponentVisualizer::GetCustomInputCoordinateSystem(const FEditorViewportClient* ViewportClient, FMatrix& OutMatrix) const | |
{ | |
if (ViewportClient->GetWidgetCoordSystemSpace() == COORD_Local) | |
{ | |
UMyComponent* EditedComp = Cast<UMyComponent>(GetEditedComponent()); | |
if (EditedComp) | |
{ | |
OutMatrix = FQuatRotationTranslationMatrix(EditedComp->GetComponentTransform().GetRotation(), FVector::ZeroVector); | |
return true; | |
} | |
} | |
return false; | |
} | |
bool FMyComponentVisualizer::IsVisualizingArchetype() const | |
{ | |
UActorComponent* EditedComp = GetEditedComponent(); | |
return (EditedComp && EditedComp->GetOwner() && FActorEditorUtils::IsAPreviewOrInactiveActor(EditedComp->GetOwner())); | |
} | |
bool FMyComponentVisualizer::HandleInputDelta(FEditorViewportClient* InViewportClient, FViewport* InViewport, FVector& InDeltaTranslate, FRotator& InDeltaRotate, FVector& InDeltaScale) | |
{ | |
if (UMyComponent* EditedComp = Cast<UMyComponent>(GetEditedComponent())) | |
{ | |
if (!InDeltaTranslate.IsZero()) | |
{ | |
EditedComp->Modify(); | |
// Find position in world space | |
const FVector CurrentWorldPos = EditedComp->GetComponentTransform().TransformPosition(EditedComp->MyVector); | |
// Move in world space | |
const FVector NewWorldPos = CurrentWorldPos + InDeltaTranslate; | |
// Convert back to local space | |
EditedComp->MyVector = EditedComp->GetComponentTransform().InverseTransformPosition(NewWorldPos); | |
} | |
NotifyPropertyModified(EditedComp, MyVectorProperty, EPropertyChangeType::Interactive); | |
GEditor->RedrawLevelEditingViewports(true); | |
return true; | |
} | |
return false; | |
} | |
void FMyComponentVisualizer::EndEditing() | |
{ | |
// Ignore if there is an undo/redo operation in progress | |
if (!GIsTransacting) | |
{ | |
ComponentPath = FComponentPropertyPath(); | |
} | |
} | |
void FMyComponentVisualizer::TrackingStopped(FEditorViewportClient* InViewportClient, bool bInDidMove) | |
{ | |
if (bInDidMove) | |
{ | |
// After dragging, notify that the property has changed one last time, this time as a EPropertyChangeType::ValueSet | |
UActorComponent* EditedComp = GetEditedComponent(); | |
NotifyPropertyModified(EditedComp, MyVectorProperty, EPropertyChangeType::ValueSet); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Copyright Feral Cat Den, LLC. All Rights Reserved. | |
#pragma once | |
#include "ComponentVisualizer.h" | |
class FMyComponentVisualizer : public FComponentVisualizer | |
{ | |
public: | |
FMyComponentVisualizer(); | |
// FComponentVisualizer API | |
virtual void DrawVisualization(const UActorComponent* InComponent, const FSceneView* InView, FPrimitiveDrawInterface* InPDI) override; | |
virtual bool VisProxyHandleClick(FEditorViewportClient* InViewportClient, HComponentVisProxy* VisProxy, const FViewportClick& Click) override; | |
virtual bool GetWidgetLocation(const FEditorViewportClient* ViewportClient, FVector& OutLocation) const override; | |
virtual bool HandleInputDelta(FEditorViewportClient* InViewportClient, FViewport* InViewport, FVector& InDeltaTranslate, FRotator& InDeltaRotate, FVector& InDeltaScale) override; | |
virtual bool GetCustomInputCoordinateSystem(const FEditorViewportClient* ViewportClient, FMatrix& OutMatrix) const override; | |
virtual void TrackingStopped(FEditorViewportClient* InViewportClient, bool bInDidMove) override; | |
virtual void EndEditing() override; | |
virtual bool IsVisualizingArchetype() const override; | |
virtual UActorComponent* GetEditedComponent() const override; | |
private: | |
FComponentPropertyPath ComponentPath; | |
FProperty* MyVectorProperty; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment