Files
UnrealEngine/Engine/Source/Developer/SourceControlViewport/Private/SourceControlViewportToolTips.cpp
2025-05-18 13:04:45 +08:00

293 lines
8.6 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "SourceControlViewportToolTips.h"
#include "SourceControlViewportUtils.h"
#include "Framework/Application/SlateApplication.h"
#include "Widgets/SToolTip.h"
#include "Widgets/SCanvas.h"
#include "Fonts/FontMeasure.h"
#include "EngineUtils.h"
#include "LevelEditor.h"
#include "SourceControlHelpers.h"
#include "ISourceControlModule.h"
#include "ISourceControlProvider.h"
#include "SLevelViewport.h"
#include "GameFramework/Actor.h"
#define LOCTEXT_NAMESPACE "SourceControlViewportToolTips"
FSourceControlViewportToolTips::FSourceControlViewportToolTips()
{
}
FSourceControlViewportToolTips::~FSourceControlViewportToolTips()
{
FTSTicker::GetCoreTicker().RemoveTicker(TickHandle);
TickHandle.Reset();
}
void FSourceControlViewportToolTips::Init()
{
TickHandle = FTSTicker::GetCoreTicker().AddTicker(
FTickerDelegate::CreateRaw(this, &FSourceControlViewportToolTips::Tick)
);
}
void FSourceControlViewportToolTips::SetEnabled(bool bInEnabled)
{
bEnabled = bInEnabled;
}
bool FSourceControlViewportToolTips::Tick(float DeltaTime)
{
UpdateCanvas(DeltaTime);
return true;
}
void FSourceControlViewportToolTips::UpdateCanvas(float DeltaTime)
{
if (CanvasWidget.IsValid())
{
// Remove the canvas if the active viewport changed.
if (GCurrentLevelEditingViewportClient != nullptr)
{
TSharedPtr<SLevelViewport> LevelViewportWidget = StaticCastSharedPtr<SLevelViewport>(GCurrentLevelEditingViewportClient->GetEditorViewportWidget());
if (LevelViewportWidget != ViewportWidget)
{
RemoveCanvas();
}
}
}
if (CanvasWidget.IsValid() && !bEnabled)
{
// Remove the canvas if the tooltips got disabled.
RemoveCanvas();
}
if (!CanvasWidget.IsValid() && bEnabled)
{
// Insert the canvas if the active viewport is perspective.
InsertCanvas();
}
if (CanvasWidget.IsValid() && ToolTipWidget.IsValid() && ViewportWidget.IsValid())
{
if (TSharedPtr<SLevelViewport> ViewportWidgetPtr = ViewportWidget.Pin())
{
FViewport* Viewport = ViewportWidgetPtr->GetViewportClient()->Viewport;
if (Viewport && Viewport->GetRenderTargetTexture())
{
int32 MouseX = Viewport->GetMouseX();
int32 MouseY = Viewport->GetMouseY();
if (ActorMouseX != MouseX || ActorMouseY != MouseY)
{
Actor.Reset();
UpdateToolTip();
ActorMouseX = MouseX;
ActorMouseY = MouseY;
}
HActor* ActorHitProxy = HitProxyCast<HActor>(Viewport->GetHitProxy(MouseX, MouseY));
if (ActorHitProxy == nullptr)
{
Actor.Reset();
UpdateToolTip();
}
if (ActorHitProxy != nullptr && ActorHitProxy->Actor != Actor)
{
Actor.Reset();
UpdateToolTip();
Actor = MakeWeakObjectPtr(ActorHitProxy->Actor);
ActorTime = FPlatformTime::Seconds();
DelayTime = 0;
}
if (Actor.IsValid())
{
DelayTime += DeltaTime;
if (DelayTime >= 0.15f) // See: Slate.TooltipSummonDelay
{
UpdateToolTip();
}
}
}
else
{
Actor.Reset();
UpdateToolTip();
}
}
}
}
void FSourceControlViewportToolTips::UpdateToolTip()
{
ToolTipText = FText::GetEmpty();
if (Actor.IsValid())
{
bool bExternal = Actor->IsPackageExternal();
bool bIgnored = !bExternal;
bool bSelected = Actor->IsSelected();
bool bHidden = Actor->IsHidden();
if (!bIgnored && !bSelected && !bHidden)
{
if (UPackage* Package = Actor->GetPackage())
{
FString SourceFileName = SourceControlHelpers::PackageFilename(Package);
ISourceControlModule& SourceControlModule = ISourceControlModule::Get();
ISourceControlProvider& SourceControlProvider = SourceControlModule.GetProvider();
if (SourceControlModule.IsEnabled())
{
FSourceControlStatePtr State = SourceControlProvider.GetState(SourceFileName, EStateCacheUsage::Use);
if (State.IsValid() && State->IsSourceControlled())
{
FString Who;
bool bNotAtHeadRevision = !State->IsCurrent();
bool bCheckedOutByOtherUser = State->IsCheckedOutOther(&Who);
bool bCheckedOut = State->IsCheckedOut();
bool bOpenForAdd = State->IsAdded();
bool bNotAtHeadRevisionEnabled = false;
bool bCheckedOutByOtherUserEnabled = false;
bool bCheckedOutEnabled = false;
bool bOpenForAddEnabled = false;
if (TSharedPtr<SLevelViewport> ViewportWidgetPtr = ViewportWidget.Pin())
{
bNotAtHeadRevisionEnabled = SourceControlViewportUtils::GetFeedbackEnabled(ViewportWidgetPtr->GetViewportClient().Get(), ESourceControlStatus::NotAtHeadRevision);
bCheckedOutByOtherUserEnabled = SourceControlViewportUtils::GetFeedbackEnabled(ViewportWidgetPtr->GetViewportClient().Get(), ESourceControlStatus::CheckedOutByOtherUser);
bCheckedOutEnabled = SourceControlViewportUtils::GetFeedbackEnabled(ViewportWidgetPtr->GetViewportClient().Get(), ESourceControlStatus::CheckedOut);
bOpenForAddEnabled = SourceControlViewportUtils::GetFeedbackEnabled(ViewportWidgetPtr->GetViewportClient().Get(), ESourceControlStatus::OpenForAdd);
}
if (bNotAtHeadRevision && bNotAtHeadRevisionEnabled)
{
ToolTipText = LOCTEXT("NotAtHeadRevision", "File(s) out of sync");
}
else if (bCheckedOutByOtherUser && bCheckedOutByOtherUserEnabled)
{
ToolTipText = FText::Format(LOCTEXT("CheckedOutOtherUser", "File(s) checked out by {0}"), FText::FromString(Who));
}
else if (bCheckedOut && bCheckedOutEnabled)
{
ToolTipText = LOCTEXT("CheckedOut", "File(s) checked out by you");
}
else if (bOpenForAdd && bOpenForAddEnabled)
{
ToolTipText = LOCTEXT("OpenForAdd", "File(s) added by you");
}
}
}
}
}
}
ToolTipWidget->SetVisibility(ToolTipText.IsEmpty() ? EVisibility::Hidden : EVisibility::Visible);
}
void FSourceControlViewportToolTips::InsertCanvas()
{
check(!CanvasWidget.IsValid());
check(!ToolTipWidget.IsValid());
check(!ViewportWidget.IsValid());
if (GCurrentLevelEditingViewportClient != nullptr && GCurrentLevelEditingViewportClient->IsPerspective())
{
TSharedPtr<SLevelViewport> LevelViewport = StaticCastSharedPtr<SLevelViewport>(GCurrentLevelEditingViewportClient->GetEditorViewportWidget());
if (LevelViewport.IsValid())
{
CanvasWidget = SNew(SCanvas)
+SCanvas::Slot()
.Position(this, &FSourceControlViewportToolTips::GetToolTipPosition)
.Size(this, &FSourceControlViewportToolTips::GetToolTipSize)
[
SAssignNew(ToolTipWidget, SToolTip)
.Font(FCoreStyle::Get().GetFontStyle("ToolTip.Font"))
.Text_Lambda([this]() { return ToolTipText; })
.Visibility(EVisibility::Hidden)
];
ViewportWidget = LevelViewport;
ViewportWidget.Pin()->AddOverlayWidget(CanvasWidget.ToSharedRef());
}
}
}
void FSourceControlViewportToolTips::RemoveCanvas()
{
if (TSharedPtr<SLevelViewport> ViewportWidgetPtr = ViewportWidget.Pin())
{
ViewportWidgetPtr->RemoveOverlayWidget(CanvasWidget.ToSharedRef());
}
CanvasWidget.Reset();
ToolTipWidget.Reset();
ViewportWidget.Reset();
}
FVector2D FSourceControlViewportToolTips::GetToolTipPosition() const
{
FVector2D Result = FVector2D::Zero();
// Taken from SlateUser.cpp
static const FVector2f TooltipOffsetFromMouse(12.0f, 8.0f);
static const FVector2f TooltipOffsetFromForceField(4.0f, 3.0f);
if (TSharedPtr<SLevelViewport> ViewportWidgetPtr = ViewportWidget.Pin())
{
FIntPoint ViewportOrigin;
FIntPoint ViewportSize;
ViewportWidgetPtr->GetViewportClient()->GetViewportDimensions(ViewportOrigin, ViewportSize);
int32 MouseX = 0;
int32 MouseY = 0;
if (FViewport* Viewport = ViewportWidgetPtr->GetViewportClient()->Viewport)
{
MouseX = Viewport->GetMouseX();
MouseY = Viewport->GetMouseY();
}
FVector2D ToolTipPos(MouseX + TooltipOffsetFromMouse.X, MouseY + TooltipOffsetFromMouse.Y);
FVector2D ToolTipSize = GetToolTipSize();
if (ToolTipPos.X + ToolTipSize.X + TooltipOffsetFromForceField.X > ViewportSize.X)
{
// Flip tooltip left so we don't overflow on the right.
ToolTipPos.X = MouseX - TooltipOffsetFromMouse.X - ToolTipSize.X;
}
if (ToolTipPos.Y + ToolTipSize.Y + TooltipOffsetFromForceField.Y > ViewportSize.Y)
{
// Flip tooltip up so we don't overflow on the bottom.
ToolTipPos.Y = MouseY - TooltipOffsetFromMouse.Y - ToolTipSize.Y;
}
Result = ToolTipPos;
}
return Result;
}
FVector2D FSourceControlViewportToolTips::GetToolTipSize() const
{
FVector2D Result = FVector2D::Zero();
if (ToolTipWidget.IsValid())
{
FSlateFontInfo FontInfo = FCoreStyle::Get().GetFontStyle("ToolTip.Font");
FVector2D TextSize = FSlateApplication::Get().GetRenderer()->GetFontMeasureService()->Measure(ToolTipText, FontInfo);
FVector2D TextMargin = FVector2D(2 * 11.f, 2 * 11.f);
Result = TextSize + TextMargin;
}
return Result;
}
#undef LOCTEXT_NAMESPACE