Files
UnrealEngine/Engine/Source/Editor/UnrealEd/Private/ComponentVisualizerManager.cpp
2025-05-18 13:04:45 +08:00

288 lines
9.2 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "ComponentVisualizerManager.h"
#include "Layout/WidgetPath.h"
#include "Framework/Application/MenuStack.h"
#include "Framework/Application/SlateApplication.h"
#include "Editor/UnrealEdEngine.h"
#include "UnrealEdGlobals.h"
#include "SEditorViewport.h"
#include "HAL/IConsoleManager.h"
#include "EditorModeManager.h"
#include "Elements/Framework/TypedElementSelectionSet.h"
FComponentVisualizerManager::FComponentVisualizerManager()
: EditedVisualizerViewportClient(nullptr)
{
}
/** Handle a click on the specified editor viewport client */
bool FComponentVisualizerManager::HandleClick(FEditorViewportClient* InViewportClient, HHitProxy* HitProxy, const FViewportClick& Click)
{
TSharedPtr<FComponentVisualizer> EditedVisualizer = EditedVisualizerPtr.Pin();
// Give current visualizer a chance to handle click if it has a modifier.
if (EditedVisualizer.IsValid() && (Click.IsControlDown() || Click.IsAltDown() || Click.IsShiftDown()))
{
if (EditedVisualizer->HandleModifiedClick(InViewportClient, HitProxy, Click))
{
return true;
}
}
bool bHandled = HandleProxyForComponentVis(InViewportClient, HitProxy, Click);
if (bHandled && Click.GetKey() == EKeys::RightMouseButton)
{
TSharedPtr<SWidget> MenuWidget = GenerateContextMenuForComponentVis();
if (MenuWidget.IsValid())
{
TSharedPtr<SEditorViewport> ViewportWidget = InViewportClient->GetEditorViewportWidget();
if (ViewportWidget.IsValid())
{
FSlateApplication::Get().PushMenu(
ViewportWidget.ToSharedRef(),
FWidgetPath(),
MenuWidget.ToSharedRef(),
FSlateApplication::Get().GetCursorPos(),
FPopupTransitionEffect(FPopupTransitionEffect::ContextMenu));
return true;
}
}
}
return bHandled;
}
bool FComponentVisualizerManager::HandleProxyForComponentVis(FEditorViewportClient* InViewportClient, HHitProxy* HitProxy, const FViewportClick& Click)
{
if (HitProxy && HitProxy->IsA(HComponentVisProxy::StaticGetType()))
{
HComponentVisProxy* VisProxy = (HComponentVisProxy*)HitProxy;
const UActorComponent* ClickedComponent = VisProxy->Component.Get();
if (ClickedComponent != NULL)
{
TSharedPtr<FComponentVisualizer> Visualizer = GUnrealEd->FindComponentVisualizer(ClickedComponent->GetClass());
if (Visualizer.IsValid())
{
FTypedElementHandle SelectedComponentHandle = VisProxy->GetElementHandle();
UTypedElementSelectionSet* ElementSelectionSet = (InViewportClient && InViewportClient->GetModeTools()) ? InViewportClient->GetModeTools()->GetEditorSelectionSet() : nullptr;
bool bIsActive = Visualizer->VisProxyHandleClick(InViewportClient, VisProxy, Click);
if (bIsActive)
{
// For spline components in particular, it is nice to select the component itself when manipulating the spline. Otherwise,
// if we have the actor selected but not the component, move a component point, and then select the component in the
// component outliner, we lose the point selection state, which feels unexpected.
bool bShouldSelectElement = Visualizer->ShouldAutoSelectElementOnHandleClick();
if (bShouldSelectElement && ElementSelectionSet)
{
if (!ElementSelectionSet->IsElementSelected(SelectedComponentHandle, FTypedElementIsSelectedOptions()))
{
ElementSelectionSet->SelectElement(SelectedComponentHandle, FTypedElementSelectionOptions());
}
}
SetActiveComponentVis(InViewportClient, Visualizer);
if (bShouldSelectElement && ElementSelectionSet)
{
ElementSelectionSet->NotifyPendingChanges();
}
return true;
}
}
}
}
// DO NOT call ClearActiveComponentVis() here. If a new actor is being selected, ClearActiveComponentVis()
// will eventually be called by UUnrealEdEngine::NoteSelectionChange(). If it were called here,
// it would be prior to the selection transaction and thus the previous state of the component visualizer
// would not be captured for undo/redo.
return false;
}
TSharedPtr<FComponentVisualizer> FComponentVisualizerManager::GetActiveComponentVis()
{
return EditedVisualizerPtr.Pin();
}
bool FComponentVisualizerManager::SetActiveComponentVis(FEditorViewportClient* InViewportClient, TSharedPtr<FComponentVisualizer>& InVisualizer)
{
if (InViewportClient && InVisualizer.IsValid())
{
// call EndEditing on any currently edited visualizer, if we are going to change it
TSharedPtr<FComponentVisualizer> EditedVisualizer = EditedVisualizerPtr.Pin();
if (EditedVisualizer.IsValid() && InVisualizer.Get() != EditedVisualizer.Get())
{
EditedVisualizer->EndEditing();
}
EditedVisualizerPtr = InVisualizer;
EditedVisualizerViewportClient = InViewportClient;
return true;
}
return false;
}
void FComponentVisualizerManager::ClearActiveComponentVis()
{
TSharedPtr<FComponentVisualizer> EditedVisualizer = EditedVisualizerPtr.Pin();
if (EditedVisualizer.IsValid())
{
EditedVisualizer->EndEditing();
}
EditedVisualizerPtr.Reset();
EditedVisualizerViewportClient = nullptr;
}
bool FComponentVisualizerManager::HandleInputKey(FEditorViewportClient* ViewportClient, FViewport* Viewport, FKey Key, EInputEvent Event) const
{
TSharedPtr<FComponentVisualizer> EditedVisualizer = EditedVisualizerPtr.Pin();
if (EditedVisualizer.IsValid())
{
return EditedVisualizer->HandleInputKey(ViewportClient, Viewport, Key, Event);
}
return false;
}
bool FComponentVisualizerManager::HandleInputDelta(FEditorViewportClient* InViewportClient, FViewport* InViewport, FVector& InDrag, FRotator& InRot, FVector& InScale) const
{
TSharedPtr<FComponentVisualizer> EditedVisualizer = EditedVisualizerPtr.Pin();
if (EditedVisualizer.IsValid() && InViewportClient && InViewportClient->GetCurrentWidgetAxis() != EAxisList::None)
{
return EditedVisualizer->HandleInputDelta(InViewportClient, InViewport, InDrag, InRot, InScale);
}
return false;
}
bool FComponentVisualizerManager::HandleFrustumSelect(const FConvexVolume& InFrustum, FEditorViewportClient* InViewportClient, FViewport* InViewport) const
{
TSharedPtr<FComponentVisualizer> EditedVisualizer = EditedVisualizerPtr.Pin();
if (EditedVisualizer.IsValid())
{
return EditedVisualizer->HandleFrustumSelect(InFrustum, InViewportClient, InViewport);
}
return false;
}
bool FComponentVisualizerManager::HandleBoxSelect(const FBox& InBox, FEditorViewportClient* InViewportClient, FViewport* InViewport) const
{
TSharedPtr<FComponentVisualizer> EditedVisualizer = EditedVisualizerPtr.Pin();
if (EditedVisualizer.IsValid())
{
return EditedVisualizer->HandleBoxSelect(InBox, InViewportClient, InViewport);
}
return false;
}
bool FComponentVisualizerManager::HasFocusOnSelectionBoundingBox(FBox& OutBoundingBox) const
{
TSharedPtr<FComponentVisualizer> EditedVisualizer = EditedVisualizerPtr.Pin();
if (EditedVisualizer.IsValid())
{
return EditedVisualizer->HasFocusOnSelectionBoundingBox(OutBoundingBox);
}
return false;
}
bool FComponentVisualizerManager::HandleSnapTo(const bool bInAlign, const bool bInUseLineTrace, const bool bInUseBounds, const bool bInUsePivot, AActor* InDestination)
{
TSharedPtr<FComponentVisualizer> EditedVisualizer = EditedVisualizerPtr.Pin();
if (EditedVisualizer.IsValid())
{
return EditedVisualizer->HandleSnapTo(bInAlign, bInUseLineTrace, bInUseBounds, bInUsePivot, InDestination);
}
return false;
}
bool FComponentVisualizerManager::GetWidgetLocation(const FEditorViewportClient* ViewportClient, FVector& OutLocation) const
{
TSharedPtr<FComponentVisualizer> EditedVisualizer = EditedVisualizerPtr.Pin();
if (EditedVisualizer.IsValid())
{
return EditedVisualizer->GetWidgetLocation(ViewportClient, OutLocation);
}
return false;
}
bool FComponentVisualizerManager::GetCustomInputCoordinateSystem(const FEditorViewportClient* ViewportClient, FMatrix& OutMatrix) const
{
TSharedPtr<FComponentVisualizer> EditedVisualizer = EditedVisualizerPtr.Pin();
if (EditedVisualizer.IsValid())
{
return EditedVisualizer->GetCustomInputCoordinateSystem(ViewportClient, OutMatrix);
}
return false;
}
void FComponentVisualizerManager::TrackingStarted(FEditorViewportClient* InViewportClient)
{
TSharedPtr<FComponentVisualizer> EditedVisualizer = EditedVisualizerPtr.Pin();
if (EditedVisualizer.IsValid())
{
return EditedVisualizer->TrackingStarted(InViewportClient);
}
}
void FComponentVisualizerManager::TrackingStopped(FEditorViewportClient* InViewportClient, bool bInDidMove)
{
TSharedPtr<FComponentVisualizer> EditedVisualizer = EditedVisualizerPtr.Pin();
if (EditedVisualizer.IsValid() && EditedVisualizer->GetEditedComponent() != nullptr)
{
return EditedVisualizer->TrackingStopped(InViewportClient, bInDidMove);
}
}
TSharedPtr<SWidget> FComponentVisualizerManager::GenerateContextMenuForComponentVis() const
{
TSharedPtr<FComponentVisualizer> EditedVisualizer = EditedVisualizerPtr.Pin();
if (EditedVisualizer.IsValid())
{
return EditedVisualizer->GenerateContextMenu();
}
return TSharedPtr<SWidget>();
}
bool FComponentVisualizerManager::IsActive() const
{
TSharedPtr<FComponentVisualizer> EditedVisualizer = EditedVisualizerPtr.Pin();
return EditedVisualizer.IsValid();
}
bool FComponentVisualizerManager::IsVisualizingArchetype() const
{
TSharedPtr<FComponentVisualizer> EditedVisualizer = EditedVisualizerPtr.Pin();
return EditedVisualizer.IsValid() && EditedVisualizer->IsVisualizingArchetype();
}