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

303 lines
8.3 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "Overrides/SOverrideStatusWidget.h"
#include "Components/HorizontalBox.h"
#include "SSimpleComboButton.h"
#include "Framework/Application/SlateApplication.h"
#include "Styling/StyleColors.h"
#include "Widgets/Images/SImage.h"
#define LOCTEXT_NAMESPACE "SOverrideStatusWidget"
SLATE_IMPLEMENT_WIDGET(SOverrideStatusWidget)
void SOverrideStatusWidget::PrivateRegisterAttributes(FSlateAttributeInitializer& AttributeInitializer)
{
}
SOverrideStatusWidget::SOverrideStatusWidget()
: WidgetStyle(nullptr)
{
}
SOverrideStatusWidget::~SOverrideStatusWidget()
{
};
void SOverrideStatusWidget::Construct(const FArguments& InArgs)
{
StatusAttribute = InArgs._Status;
OnGetMenuContent = InArgs._MenuContent;
OnClicked = InArgs._OnClicked;
bAlwaysUpdateOnTick = false;
bTickIsPending = false;
if(InArgs._IsHovered.IsBound())
{
SetHover(InArgs._IsHovered);
}
if(InArgs._DefaultStyle.IsSet())
{
DefaultWidgetStyle = InArgs._DefaultStyle.GetValue();
}
else
{
if(const FOverrideStatusWidgetStyle* StyleFromStatus = GetStyleFromStatus(EOverrideWidgetStatus::Undetermined))
{
DefaultWidgetStyle = *StyleFromStatus;
}
}
WidgetStyle = nullptr;
OnGetStyle = InArgs._Style;
OnGetTooltip = InArgs._Tooltip;
if(!OnGetStyle.IsBound())
{
OnGetStyle.BindStatic(&SOverrideStatusWidget::GetStyleFromStatus_Fallback);
bAlwaysUpdateOnTick = StatusAttribute.IsBound();
}
ChildSlot
[
SAssignNew(Image, SImage)
];
}
FReply SOverrideStatusWidget::OnMouseButtonUp(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent)
{
return FReply::Handled();
}
void SOverrideStatusWidget::OnMouseEnter(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent)
{
SCompoundWidget::OnMouseEnter(MyGeometry, MouseEvent);
if(!GetHoveredAttribute().IsBound())
{
SetHover(true);
}
QueueRepaint();
}
void SOverrideStatusWidget::OnMouseLeave(const FPointerEvent& MouseEvent)
{
SCompoundWidget::OnMouseLeave(MouseEvent);
if(!GetHoveredAttribute().IsBound())
{
SetHover(false);
}
QueueRepaint();
}
void SOverrideStatusWidget::QueueRepaint()
{
Invalidate(EInvalidateWidgetReason::Paint);
SetCanTick(true);
bTickIsPending = true;
}
FReply SOverrideStatusWidget::OnMouseButtonDown(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent)
{
if (MouseEvent.GetEffectingButton() != EKeys::LeftMouseButton)
{
return FReply::Unhandled();
}
return HandleClick();
}
FReply SOverrideStatusWidget::HandleClick()
{
// Create the overrides menu at the cursor location
if(OnClicked.IsBound())
{
const FReply ReplyFromDelegate = OnClicked.Execute();
if(ReplyFromDelegate.IsEventHandled())
{
return ReplyFromDelegate;
}
}
if (OnGetMenuContent.IsBound())
{
const TSharedRef<SWidget> Content = OnGetMenuContent.Execute();
if(Content != SNullWidget::NullWidget)
{
FSlateApplication::Get().PushMenu(
SharedThis(this),
FWidgetPath(),
Content,
FSlateApplication::Get().GetCursorPos(),
FPopupTransitionEffect(FPopupTransitionEffect::TypeInPopup));
return FReply::Handled();
}
}
return FReply::Unhandled();
}
EOverrideWidgetStatus::Type SOverrideStatusWidget::GetStatus() const
{
return StatusAttribute.Get(EOverrideWidgetStatus::Undetermined);
}
void SOverrideStatusWidget::SetStatus(EOverrideWidgetStatus::Type InStatus)
{
StatusAttribute = InStatus;
QueueRepaint();
}
const FOverrideStatusWidgetStyle* SOverrideStatusWidget::GetStyleFromStatus_Fallback(EOverrideWidgetStatus::Type InStatus)
{
return GetStyleFromStatus(InStatus);
}
void SOverrideStatusWidget::Tick(
const FGeometry& AllottedGeometry,
const double InCurrentTime,
const float InDeltaTime)
{
TRACE_CPUPROFILER_EVENT_SCOPE(SOverrideStatusWidget::Tick);
if(!bAlwaysUpdateOnTick)
{
// Only need to tick on first run or if the data changes which trigger a repaint
// Paint will tick us.
SetCanTick(false);
}
else
{
bTickIsPending = true;
}
if(bTickIsPending)
{
// Figure out what type of Icon we need
const FOverrideStatusWidgetStyle* Style = nullptr;
if (OnGetStyle.IsBound())
{
Style = OnGetStyle.Execute(GetStatus());
}
const FOverrideStatusWidgetStyle* NewWidgetStyle = Style ? Style : &DefaultWidgetStyle;
if(NewWidgetStyle != WidgetStyle)
{
WidgetStyle = NewWidgetStyle;
Image->SetDesiredSizeOverride(WidgetStyle->IconSize);
Image->SetToolTipText(WidgetStyle->Tooltip);
bLastHovered.Reset();
}
const bool bIsHovered = IsHovered();
if (bIsHovered != bLastHovered.Get(!bIsHovered))
{
bLastHovered = bIsHovered;
if(bIsHovered)
{
Image->SetImage(WidgetStyle->HoveredIcon);
Image->SetColorAndOpacity(WidgetStyle->HoveredColor);
}
else
{
Image->SetImage(WidgetStyle->Icon);
Image->SetColorAndOpacity(WidgetStyle->Color);
}
}
bTickIsPending = false;
}
Super::Tick(AllottedGeometry, InCurrentTime, InDeltaTime);
}
const FOverrideStatusWidgetStyle* SOverrideStatusWidget::GetStyleFromStatus(EOverrideWidgetStatus::Type InStatus)
{
static const TMap<EOverrideWidgetStatus::Type, FOverrideStatusWidgetStyle> StyleMap =
{
{ // No override
EOverrideWidgetStatus::None,
{
.Icon = FAppStyle::GetBrush(TEXT("DetailsView.OverrideNone")),
.HoveredIcon = FAppStyle::GetBrush(TEXT("DetailsView.OverrideNone.Hovered")),
.Tooltip = LOCTEXT("NoOverridePropertyToolTip", "No override."),
.IconSize = FVector2D(16, 16),
}
},
{ // Undetermined
EOverrideWidgetStatus::Undetermined,
{
.Icon = FAppStyle::GetBrush(TEXT("DetailsView.OverrideUndetermined")),
.HoveredIcon = FAppStyle::GetBrush(TEXT("DetailsView.OverrideUndetermined")),
.Tooltip = LOCTEXT("UndeterminedPropertyToolTip", "State has not yet been determined"),
.IconSize = FVector2D(16, 16),
},
},
{ // uninitialized
EOverrideWidgetStatus::Uninitialized,
{
.Icon = FAppStyle::GetBrush(TEXT("DetailsView.OverrideAlert")),
.HoveredIcon = FAppStyle::GetBrush(TEXT("DetailsView.OverrideAlert.Hovered")),
.Tooltip = LOCTEXT("NonConcreteUninitialized", "This property needs a value.\nYou won't be able to test or publish until you set one."),
.Color = FStyleColors::Error,
.IconSize = FVector2D(16, 16),
}
},
{ // Inherited
EOverrideWidgetStatus::Inherited,
{
.Icon = FAppStyle::GetBrush(TEXT("DetailsView.OverrideInherited")),
.HoveredIcon = FAppStyle::GetBrush(TEXT("DetailsView.OverrideInherited.Hovered")),
.Tooltip = LOCTEXT("InheritedPropertyToolTip", "This property's parent component has been overridden."),
.HoveredColor = FColor::White,
.IconSize = FVector2D(16, 16),
}
},
{ // Here
EOverrideWidgetStatus::ChangedHere,
{
.Icon = FAppStyle::GetBrush(TEXT("DetailsView.OverrideHere")),
.HoveredIcon = FAppStyle::GetBrush(TEXT("DetailsView.OverrideHere.Hovered")),
.Tooltip = LOCTEXT("HerePropertyToolTip", "This property has been overridden."),
.HoveredColor = FColor::White,
.IconSize = FVector2D(16, 16),
}
},
{ // Inside
EOverrideWidgetStatus::ChangedInside,
{
.Icon = FAppStyle::GetBrush(TEXT("DetailsView.OverrideInside")),
.HoveredIcon = FAppStyle::GetBrush(TEXT("DetailsView.OverrideInside.Hovered")),
.Tooltip = LOCTEXT("InsidePropertyToolTip", "At least one of this property's values has been overridden."),
.HoveredColor = FColor::White,
.IconSize = FVector2D(16, 16),
}
},
{ // Outside
EOverrideWidgetStatus::ChangedOutside,
{
.Icon = FAppStyle::GetBrush(TEXT("DetailsView.OverrideInherited")),
.HoveredIcon = FAppStyle::GetBrush(TEXT("DetailsView.OverrideInherited.Hovered")),
.Tooltip = LOCTEXT("OverrideInheritedToolTip", "A parent of this property has been overridden."),
.HoveredColor = FColor::White,
.IconSize = FVector2D(16, 16),
}
},
{ // Mixed
EOverrideWidgetStatus::Mixed,
{
.Icon = FAppStyle::GetBrush(TEXT("DetailsView.OverrideMixed")),
.HoveredIcon = FAppStyle::GetBrush(TEXT("DetailsView.OverrideMixed.Hovered")),
.Tooltip = LOCTEXT("OverrideMixedToolTip", "The selected elements have mixed override states on this property."),
.HoveredColor = FColor::White,
.IconSize = FVector2D(16, 16),
}
}
};
return StyleMap.Find(InStatus);
}
#undef LOCTEXT_NAMESPACE