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

1034 lines
41 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "SAnimViewportToolBar.h"
#include "AnimViewportToolBarToolMenuContext.h"
#include "AnimPreviewInstance.h"
#include "Widgets/Layout/SBorder.h"
#include "Widgets/Text/STextBlock.h"
#include "Framework/MultiBox/MultiBoxBuilder.h"
#include "ToolMenus.h"
#include "EngineGlobals.h"
#include "AssetRegistry/AssetData.h"
#include "Engine/Engine.h"
#include "Styling/AppStyle.h"
#include "PropertyEditorModule.h"
#include "IDetailsView.h"
#include "Framework/Application/SlateApplication.h"
#include "Editor/EditorPerProjectUserSettings.h"
#include "Preferences/PersonaOptions.h"
#include "EditorViewportCommands.h"
#include "AnimViewportMenuCommands.h"
#include "AnimViewportShowCommands.h"
#include "AnimViewportPlaybackCommands.h"
#include "SEditorViewportToolBarMenu.h"
#include "STransformViewportToolbar.h"
#include "SEditorViewportViewMenu.h"
#include "Widgets/Input/SNumericEntryBox.h"
#include "Widgets/Input/STextComboBox.h"
#include "AssetViewerSettings.h"
#include "PreviewSceneCustomizations.h"
#include "SimulationEditorExtender.h"
#include "ClothingSimulationFactory.h"
#include "ClothingSystemEditorInterfaceModule.h"
#include "Widgets/SWidget.h"
#include "Types/ISlateMetaData.h"
#include "Textures/SlateIcon.h"
#include "BufferVisualizationMenuCommands.h"
#include "IPinnedCommandList.h"
#include "UICommandList_Pinnable.h"
#include "ContentBrowserModule.h"
#include "IContentBrowserSingleton.h"
#include "SCommonEditorViewportToolbarBase.h"
#include "Animation/MirrorDataTable.h"
#include "ScopedTransaction.h"
#include "ViewportToolbar/AnimationEditorMenus.h"
#include "ViewportToolbar/AnimationEditorWidgets.h"
#include "ViewportToolbar/UnrealEdViewportToolbar.h"
#define LOCTEXT_NAMESPACE "AnimViewportToolBar"
///////////////////////////////////////////////////////////
// SAnimViewportToolBar
void SAnimViewportToolBar::Construct(
const FArguments& InArgs,
TSharedPtr<class SAnimationEditorViewportTabBody> InViewport,
TSharedPtr<class SEditorViewport> InRealViewport
)
{
bShowShowMenu = InArgs._ShowShowMenu;
bShowCharacterMenu = InArgs._ShowCharacterMenu;
bShowLODMenu = InArgs._ShowLODMenu;
bShowPlaySpeedMenu = InArgs._ShowPlaySpeedMenu;
bShowFloorOptions = InArgs._ShowFloorOptions;
bShowTurnTable = InArgs._ShowTurnTable;
bShowPhysicsMenu = InArgs._ShowPhysicsMenu;
if (!InRealViewport)
{
return;
}
CommandList = InRealViewport->GetCommandList();
Extenders = InArgs._Extenders;
Extenders.Add(GetViewMenuExtender(InRealViewport));
// If we have no extender, make an empty one
if (Extenders.Num() == 0)
{
Extenders.Add(MakeShared<FExtender>());
}
const FMargin ToolbarSlotPadding(4.0f, 1.0f);
const FMargin ToolbarButtonPadding(4.0f, 1.0f);
// clang-format off
TSharedRef<SHorizontalBox> LeftToolbar =
SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
.AutoWidth()
.Padding(ToolbarSlotPadding)
[
SNew(SEditorViewportToolbarMenu)
.ToolTipText(LOCTEXT("ViewMenuTooltip", "View Options.\nShift-clicking items will 'pin' them to the toolbar."))
.ParentToolBar(SharedThis(this))
.Cursor(EMouseCursor::Default)
.Image("EditorViewportToolBar.OptionsDropdown")
.AddMetaData<FTagMetaData>(FTagMetaData(TEXT("EditorViewportToolBar.MenuDropdown")))
.OnGetMenuContent(this, &SAnimViewportToolBar::GenerateViewMenu)
]
+ SHorizontalBox::Slot()
.AutoWidth()
.Padding(ToolbarSlotPadding)
[
SNew(SEditorViewportToolbarMenu)
.ToolTipText(LOCTEXT("ViewportMenuTooltip", "Viewport Options. Use this to switch between different orthographic or perspective views."))
.ParentToolBar(SharedThis(this))
.Cursor(EMouseCursor::Default)
.Label(this, &SAnimViewportToolBar::GetCameraMenuLabel)
.LabelIcon(this, &SAnimViewportToolBar::GetCameraMenuLabelIcon)
.AddMetaData<FTagMetaData>(FTagMetaData(TEXT("EditorViewportToolBar.CameraMenu")))
.OnGetMenuContent(this, &SAnimViewportToolBar::GenerateViewportTypeMenu)
]
// View menu (lit, unlit, etc...)
+ SHorizontalBox::Slot()
.AutoWidth()
.Padding(ToolbarSlotPadding)
[
SNew(SEditorViewportViewMenu, InRealViewport.ToSharedRef(), SharedThis(this))
.ToolTipText(LOCTEXT("ViewModeMenuTooltip", "View Mode Options. Use this to change how the view is rendered, e.g. Lit/Unlit."))
.MenuExtenders(FExtender::Combine(Extenders))
]
+ SHorizontalBox::Slot()
.AutoWidth()
.Padding(ToolbarSlotPadding)
[
SNew(SEditorViewportToolbarMenu)
.ToolTipText(LOCTEXT("ShowMenuTooltip", "Show Options. Use this enable/disable the rendering of types of scene elements."))
.ParentToolBar(SharedThis(this))
.Cursor(EMouseCursor::Default)
.Label(LOCTEXT("ShowMenu", "Show"))
.AddMetaData<FTagMetaData>(FTagMetaData(TEXT("ViewMenuButton")))
.OnGetMenuContent(this, &SAnimViewportToolBar::GenerateShowMenu)
]
+ SHorizontalBox::Slot()
.AutoWidth()
.Padding(ToolbarSlotPadding)
[
SNew(SPreviewSceneProfileSelector)
.PreviewProfileController(InRealViewport->GetPreviewProfileController())
.Visibility_Lambda(
[ViewportWidgetWeak = InRealViewport.ToWeakPtr()]()
{
if (TSharedPtr<SEditorViewport> ViewportWidget = ViewportWidgetWeak.Pin())
{
// only show this menu if the user has customized it by adding their own profiles
// this behavior was requested by UX to match the behavior of the static mesh editor
if (TSharedPtr<IPreviewProfileController> PreviewProfileController = ViewportWidget->GetPreviewProfileController())
{
return PreviewProfileController->HasAnyUserProfiles() ? EVisibility::Visible
: EVisibility::Collapsed;
}
}
return EVisibility::Hidden;
})
]
+ SHorizontalBox::Slot()
.AutoWidth()
.Padding(ToolbarSlotPadding)
[
SNew(SEditorViewportToolbarMenu)
.ToolTipText(LOCTEXT("PhysicsMenuTooltip", "Physics Options. Use this to control the physics of the scene."))
.ParentToolBar(SharedThis(this))
.Label(LOCTEXT("Physics", "Physics"))
.OnGetMenuContent(this, &SAnimViewportToolBar::GeneratePhysicsMenu)
.Visibility(bShowPhysicsMenu ? EVisibility::Visible : EVisibility::Collapsed)
]
+ SHorizontalBox::Slot()
.AutoWidth()
.Padding(ToolbarSlotPadding)
[
SNew(SEditorViewportToolbarMenu)
.ToolTipText(LOCTEXT("CharacterMenuTooltip", "Character Options. Control character-related rendering options.\nShift-clicking items will 'pin' them to the toolbar."))
.ParentToolBar(SharedThis(this))
.Label(LOCTEXT("Character", "Character"))
.OnGetMenuContent(this, &SAnimViewportToolBar::GenerateCharacterMenu)
.Visibility(bShowCharacterMenu ? EVisibility::Visible : EVisibility::Collapsed)
]
+ SHorizontalBox::Slot()
.AutoWidth()
.Padding(ToolbarSlotPadding)
[
//LOD
SNew(SEditorViewportToolbarMenu)
.ToolTipText(LOCTEXT("LODMenuTooltip", "LOD Options. Control how LODs are displayed.\nShift-clicking items will 'pin' them to the toolbar."))
.ParentToolBar(SharedThis(this))
.Label(this, &SAnimViewportToolBar::GetLODMenuLabel)
.OnGetMenuContent(this, &SAnimViewportToolBar::GenerateLODMenu)
]
+ SHorizontalBox::Slot()
.AutoWidth()
.Padding(ToolbarSlotPadding)
[
SNew(SEditorViewportToolbarMenu)
.ToolTipText(LOCTEXT("PlaybackSpeedMenuTooltip", "Playback Speed Options. Control the time dilation of the scene's update.\nShift-clicking items will 'pin' them to the toolbar."))
.ParentToolBar(SharedThis(this))
.Label(this, &SAnimViewportToolBar::GetPlaybackMenuLabel)
.LabelIcon(FAppStyle::GetBrush("AnimViewportMenu.PlayBackSpeed"))
.OnGetMenuContent(this, &SAnimViewportToolBar::GeneratePlaybackMenu)
]
+ SHorizontalBox::Slot()
.Padding(ToolbarSlotPadding)
.HAlign(HAlign_Right)
[
SNew(STransformViewportToolBar)
.Viewport(InRealViewport)
.CommandList(InRealViewport->GetCommandList())
.Visibility(this, &SAnimViewportToolBar::GetTransformToolbarVisibility)
.OnCamSpeedChanged(this, &SAnimViewportToolBar::OnCamSpeedChanged)
.OnCamSpeedScalarChanged(this, &SAnimViewportToolBar::OnCamSpeedScalarChanged)
];
// clang-format on
TWeakPtr<SAnimViewportToolBar> AnimViewportToolbarWeak = SharedThis(this);
UE::UnrealEd::OnViewportClientCamSpeedChanged().BindLambda(
[AnimViewportToolbarWeak, EditorViewportWeak = InRealViewport.ToWeakPtr()](const TSharedRef<SEditorViewport>& InEditorViewport, int32 InNewValue)
{
TSharedPtr<SAnimViewportToolBar> AnimViewportToolbar = AnimViewportToolbarWeak.Pin();
if (!AnimViewportToolbar)
{
return;
}
if (TSharedPtr<SEditorViewport> EditorViewport = EditorViewportWeak.Pin())
{
if (EditorViewport == InEditorViewport)
{
AnimViewportToolbar->OnCamSpeedChanged(InNewValue);
}
}
}
);
UE::UnrealEd::OnViewportClientCamSpeedScalarChanged().BindLambda(
[AnimViewportToolbarWeak, EditorViewportWeak = InRealViewport.ToWeakPtr()](const TSharedRef<SEditorViewport>& InEditorViewport, float InNewValue)
{
TSharedPtr<SAnimViewportToolBar> AnimViewportToolbar = AnimViewportToolbarWeak.Pin();
if (!AnimViewportToolbar)
{
return;
}
if (TSharedPtr<SEditorViewport> EditorViewport = EditorViewportWeak.Pin())
{
if (EditorViewport == InEditorViewport)
{
AnimViewportToolbar->OnCamSpeedScalarChanged(InNewValue);
}
}
}
);
//@TODO: Need clipping horizontal box: LeftToolbar->AddWrapButton();
TSharedPtr<IPinnedCommandList> PinnedCommands = InViewport->GetPinnedCommands();
// clang-format off
ChildSlot
[
SNew(SVerticalBox)
+ SVerticalBox::Slot()
.AutoHeight()
[
SNew(SBorder)
.BorderImage(FAppStyle::Get().GetBrush("EditorViewportToolBar.Background"))
.Cursor(EMouseCursor::Default)
[
LeftToolbar
]
]
];
// clang-format on
SViewportToolBar::Construct(SViewportToolBar::FArguments());
if (PinnedCommands)
{
// Register all the custom widgets we can use here
PinnedCommands->RegisterCustomWidget(
IPinnedCommandList::FOnGenerateCustomWidget::CreateSP(this, &SAnimViewportToolBar::MakeFloorOffsetWidget),
TEXT("FloorOffsetWidget"),
LOCTEXT("FloorHeightOffset", "Floor Height Offset")
);
PinnedCommands->RegisterCustomWidget(
IPinnedCommandList::FOnGenerateCustomWidget::CreateSP(this, &SAnimViewportToolBar::MakeFOVWidget),
TEXT("FOVWidget"),
LOCTEXT("Viewport_FOVLabel", "Field Of View")
);
}
// We assign the viewport pointer here rather than initially, as SViewportToolbar::Construct
// ends up calling through and attempting to perform operations on the not-yet-full-constructed viewport
Viewport = InViewport;
}
EVisibility SAnimViewportToolBar::GetTransformToolbarVisibility() const
{
return Viewport.Pin()->CanUseGizmos() ? EVisibility::Visible : EVisibility::Hidden;
}
TSharedRef<SWidget> SAnimViewportToolBar::MakeFloorOffsetWidget() const
{
return UE::AnimationEditor::MakeFloorOffsetWidget(Viewport);
}
TSharedRef<SWidget> SAnimViewportToolBar::MakeFOVWidget() const
{
const float FOVMin = 5.f;
const float FOVMax = 170.f;
return
SNew(SBox)
.HAlign(HAlign_Right)
[
SNew(SBox)
.Padding(FMargin(4.0f, 0.0f, 0.0f, 0.0f))
.WidthOverride(100.0f)
[
SNew(SNumericEntryBox<float>)
.Font(FAppStyle::GetFontStyle(TEXT("MenuItem.Font")))
.AllowSpin(true)
.MinValue(FOVMin)
.MaxValue(FOVMax)
.MinSliderValue(FOVMin)
.MaxSliderValue(FOVMax)
.Value(this, &SAnimViewportToolBar::OnGetFOVValue)
.OnValueChanged(const_cast<SAnimViewportToolBar*>(this), &SAnimViewportToolBar::OnFOVValueChanged)
.OnValueCommitted(const_cast<SAnimViewportToolBar*>(this), &SAnimViewportToolBar::OnFOVValueCommitted)
]
];
}
TSharedRef<SWidget> SAnimViewportToolBar::MakeFollowBoneComboWidget() const
{
TSharedRef<SComboButton> ComboButton = SNew(SComboButton)
.ComboButtonStyle(FAppStyle::Get(), "ViewportPinnedCommandList.ComboButton")
.ContentPadding(0.0f)
.ButtonContent()
[
SNew(STextBlock)
.TextStyle(FAppStyle::Get(), "ViewportPinnedCommandList.Label")
.Text_Lambda([this]()
{
const FName BoneName = Viewport.Pin()->GetCameraFollowBoneName();
if(BoneName != NAME_None)
{
return FText::Format(LOCTEXT("FollowingBoneMenuTitleFormat", "Following Bone: {0}"), FText::FromName(BoneName));
}
else
{
return LOCTEXT("FollowBoneMenuTitle", "Focus On Bone");
}
})
];
TWeakPtr<SComboButton> WeakComboButton = ComboButton;
ComboButton->SetOnGetMenuContent(FOnGetContent::CreateLambda(
[ViewportWeak = Viewport, WeakComboButton]()
{
return UE::AnimationEditor::MakeFollowBoneWidget(ViewportWeak, WeakComboButton);
}
));
return ComboButton;
}
TSharedRef<SWidget> SAnimViewportToolBar::MakeFollowBoneWidget() const
{
return UE::AnimationEditor::MakeFollowBoneWidget(Viewport, nullptr);
}
TSharedRef<SWidget> SAnimViewportToolBar::GenerateViewMenu() const
{
const FAnimViewportMenuCommands& Actions = FAnimViewportMenuCommands::Get();
TSharedPtr<FExtender> MenuExtender = FExtender::Combine(Extenders);
const bool bInShouldCloseWindowAfterMenuSelection = true;
FMenuBuilder InMenuBuilder(bInShouldCloseWindowAfterMenuSelection, Viewport.Pin()->GetCommandList(), MenuExtender);
InMenuBuilder.PushCommandList(Viewport.Pin()->GetCommandList().ToSharedRef());
InMenuBuilder.PushExtender(MenuExtender.ToSharedRef());
InMenuBuilder.BeginSection("AnimViewportSceneSetup", LOCTEXT("ViewMenu_SceneSetupLabel", "Scene Setup"));
{
InMenuBuilder.PushCommandList(Viewport.Pin()->GetCommandList().ToSharedRef());
InMenuBuilder.AddMenuEntry(FAnimViewportMenuCommands::Get().PreviewSceneSettings);
InMenuBuilder.PopCommandList();
if(bShowFloorOptions)
{
InMenuBuilder.AddWidget(MakeFloorOffsetWidget(), LOCTEXT("FloorHeightOffset", "Floor Height Offset"));
InMenuBuilder.PushCommandList(Viewport.Pin()->GetCommandList().ToSharedRef());
InMenuBuilder.AddMenuEntry(FAnimViewportShowCommands::Get().AutoAlignFloorToMesh);
InMenuBuilder.PopCommandList();
}
if (bShowTurnTable)
{
InMenuBuilder.AddSubMenu(
LOCTEXT("TurnTableLabel", "Turn Table"),
LOCTEXT("TurnTableTooltip", "Set up auto-rotation of preview."),
FNewMenuDelegate::CreateRaw(this, &SAnimViewportToolBar::GenerateTurnTableMenu),
false,
FSlateIcon(FAppStyle::GetAppStyleSetName(), "AnimViewportMenu.TurnTableSpeed")
);
}
}
InMenuBuilder.EndSection();
InMenuBuilder.BeginSection("AnimViewportCamera", LOCTEXT("ViewMenu_CameraLabel", "Camera"));
{
InMenuBuilder.AddMenuEntry(FEditorViewportCommands::Get().FocusViewportToSelection);
InMenuBuilder.AddWidget(MakeFOVWidget(), LOCTEXT("Viewport_FOVLabel", "Field Of View"));
InMenuBuilder.AddMenuEntry(FAnimViewportMenuCommands::Get().TogglePauseAnimationOnCameraMove);
InMenuBuilder.AddSubMenu(
LOCTEXT("CameraFollowModeLabel", "Follow Mode"),
LOCTEXT("CameraFollowModeTooltip", "Set various camera follow modes"),
FNewMenuDelegate::CreateLambda([ViewportWeak = Viewport](FMenuBuilder& InSubMenuBuilder)
{
InSubMenuBuilder.BeginSection(NAME_None, FText());
{
InSubMenuBuilder.AddWidget(UE::AnimationEditor::CreateFollowModeMenuWidget(ViewportWeak), FText());
}
InSubMenuBuilder.EndSection();
}),
false,
FSlateIcon(FAppStyle::GetAppStyleSetName(), "AnimViewportMenu.CameraFollow")
);
}
InMenuBuilder.EndSection();
InMenuBuilder.BeginSection("AnimViewportDefaultCamera", LOCTEXT("ViewMenu_DefaultCameraLabel", "Default Camera"));
{
InMenuBuilder.PushCommandList(Viewport.Pin()->GetCommandList().ToSharedRef());
InMenuBuilder.AddMenuEntry(FAnimViewportMenuCommands::Get().JumpToDefaultCamera);
InMenuBuilder.AddMenuEntry(FAnimViewportMenuCommands::Get().SaveCameraAsDefault);
InMenuBuilder.AddMenuEntry(FAnimViewportMenuCommands::Get().ClearDefaultCamera);
InMenuBuilder.PopCommandList();
}
InMenuBuilder.EndSection();
InMenuBuilder.PopCommandList();
InMenuBuilder.PopExtender();
return InMenuBuilder.MakeWidget();
}
TSharedRef<SWidget> SAnimViewportToolBar::GeneratePhysicsMenu() const
{
return UE::AnimationEditor::GeneratePhysicsMenuWidget(Viewport, FExtender::Combine(Extenders));
}
TSharedRef<SWidget> SAnimViewportToolBar::GenerateCharacterMenu() const
{
static const FName MenuName("Persona.AnimViewportCharacterMenu");
if (!UToolMenus::Get()->IsMenuRegistered(MenuName))
{
UToolMenu* Menu = UToolMenus::Get()->RegisterMenu(MenuName);
{
FToolMenuSection& Section = Menu->AddSection("AnimViewportSceneElements", LOCTEXT("CharacterMenu_SceneElements", "Scene Elements"));
Section.AddSubMenu(TEXT("MeshSubMenu"),
LOCTEXT("CharacterMenu_MeshSubMenu", "Mesh"),
LOCTEXT("CharacterMenu_MeshSubMenuToolTip", "Mesh-related options"),
FNewToolMenuDelegate::CreateLambda([](UToolMenu* InSubMenu)
{
{
FToolMenuSection& Section = InSubMenu->AddSection("AnimViewportMesh", LOCTEXT("CharacterMenu_Actions_Mesh", "Mesh"));
Section.AddMenuEntry(FAnimViewportShowCommands::Get().ShowBound);
Section.AddMenuEntry(FAnimViewportShowCommands::Get().UseInGameBound);
Section.AddMenuEntry(FAnimViewportShowCommands::Get().UseFixedBounds);
Section.AddMenuEntry(FAnimViewportShowCommands::Get().UsePreSkinnedBounds);
Section.AddMenuEntry(FAnimViewportShowCommands::Get().ShowPreviewMesh);
Section.AddMenuEntry(FAnimViewportShowCommands::Get().ShowMorphTargets);
}
{
FToolMenuSection& Section = InSubMenu->AddSection("AnimViewportMeshInfo", LOCTEXT("CharacterMenu_Actions_MeshInfo", "Mesh Info"));
Section.AddMenuEntry(FAnimViewportShowCommands::Get().ShowDisplayInfoBasic);
Section.AddMenuEntry(FAnimViewportShowCommands::Get().ShowDisplayInfoDetailed);
Section.AddMenuEntry(FAnimViewportShowCommands::Get().ShowDisplayInfoSkelControls);
Section.AddMenuEntry(FAnimViewportShowCommands::Get().HideDisplayInfo);
}
{
FToolMenuSection& Section = InSubMenu->AddSection("AnimViewportPreviewOverlayDraw", LOCTEXT("CharacterMenu_Actions_Overlay", "Mesh Overlay Drawing"));
Section.AddMenuEntry(FAnimViewportShowCommands::Get().ShowOverlayNone);
Section.AddMenuEntry(FAnimViewportShowCommands::Get().ShowBoneWeight);
Section.AddMenuEntry(FAnimViewportShowCommands::Get().ShowMorphTargetVerts);
}
})
);
Section.AddSubMenu(TEXT("AnimationSubMenu"),
LOCTEXT("CharacterMenu_AnimationSubMenu", "Animation"),
LOCTEXT("CharacterMenu_AnimationSubMenuToolTip", "Animation-related options"),
FNewToolMenuDelegate::CreateLambda([](UToolMenu* InSubMenu)
{
UAnimViewportToolBarToolMenuContext* Context = InSubMenu->FindContext<UAnimViewportToolBarToolMenuContext>();
const SAnimViewportToolBar* ContextThis = Context ? Context->AnimViewportToolBar.Pin().Get() : nullptr;
{
FToolMenuSection& Section = InSubMenu->AddSection("AnimViewportRootMotion", LOCTEXT("CharacterMenu_RootMotionLabel", "Root Motion"));
Section.AddMenuEntry(FAnimViewportShowCommands::Get().DoNotProcessRootMotion);
Section.AddMenuEntry(FAnimViewportShowCommands::Get().ProcessRootMotionLoop);
Section.AddMenuEntry(FAnimViewportShowCommands::Get().ProcessRootMotionLoopAndReset);
}
{
FToolMenuSection& Section = InSubMenu->AddSection("AnimViewportVisualization", LOCTEXT("CharacterMenu_VisualizationsLabel", "Visualizations"));
Section.AddMenuEntry(FAnimViewportShowCommands::Get().ShowNotificationVisualizations);
Section.AddMenuEntry(FAnimViewportShowCommands::Get().DoNotVisualizeRootMotion);
Section.AddMenuEntry(FAnimViewportShowCommands::Get().VisualizeRootMotionTrajectory);
Section.AddMenuEntry(FAnimViewportShowCommands::Get().VisualizeRootMotionTrajectoryAndOrientation);
Section.AddMenuEntry(FAnimViewportShowCommands::Get().ShowAssetUserDataVisualizations);
}
{
FToolMenuSection& Section = InSubMenu->AddSection("AnimViewportAnimation", LOCTEXT("CharacterMenu_Actions_AnimationAsset", "Animation"));
Section.AddMenuEntry(FAnimViewportShowCommands::Get().ShowRawAnimation);
Section.AddMenuEntry(FAnimViewportShowCommands::Get().ShowNonRetargetedAnimation);
Section.AddMenuEntry(FAnimViewportShowCommands::Get().ShowAdditiveBaseBones);
Section.AddMenuEntry(FAnimViewportShowCommands::Get().ShowSourceRawAnimation);
if (ContextThis && ContextThis->Viewport.IsValid())
{
if ( UDebugSkelMeshComponent* PreviewComponent = ContextThis->Viewport.Pin()->GetPreviewScene()->GetPreviewMeshComponent())
{
FUIAction DisableUnlessPreviewInstance(
FExecuteAction::CreateLambda([](){}),
FCanExecuteAction::CreateLambda([PreviewComponent]()
{
return (PreviewComponent->PreviewInstance && (PreviewComponent->PreviewInstance == PreviewComponent->GetAnimInstance() ) );
})
);
Section.AddSubMenu(TEXT("MirrorSubMenu"),
LOCTEXT("CharacterMenu_AnimationSubMenu_MirrorSubMenu", "Mirror"),
LOCTEXT("CharacterMenu_AnimationSubMenu_MirrorSubMenuToolTip", "Mirror the animation using the selected mirror data table"),
FNewToolMenuChoice(FNewMenuDelegate::CreateRaw(ContextThis, &SAnimViewportToolBar::FillCharacterMirrorMenu)),
FToolUIActionChoice(DisableUnlessPreviewInstance),
EUserInterfaceActionType::Button,
false,
FSlateIcon(),
false);
}
}
Section.AddMenuEntry(FAnimViewportShowCommands::Get().ShowBakedAnimation);
Section.AddMenuEntry(FAnimViewportShowCommands::Get().DisablePostProcessBlueprint);
}
if (ContextThis && ContextThis->Viewport.IsValid())
{
FToolMenuSection& Section = InSubMenu->AddSection("SkinWeights", LOCTEXT("SkinWeights_Label", "Skin Weight Profiles"));
Section.AddEntry(FToolMenuEntry::InitWidget(TEXT("SkinWeightCombo"), ContextThis->Viewport.Pin()->SkinWeightCombo.ToSharedRef(), FText()));
}
})
);
Section.AddSubMenu(TEXT("BonesSubMenu"),
LOCTEXT("CharacterMenu_BoneDrawSubMenu", "Bones"),
LOCTEXT("CharacterMenu_BoneDrawSubMenuToolTip", "Bone Drawing Options"),
FNewToolMenuDelegate::CreateLambda([](UToolMenu* InSubMenu)
{
UAnimViewportToolBarToolMenuContext* Context = InSubMenu->FindContext<UAnimViewportToolBarToolMenuContext>();
const SAnimViewportToolBar* ContextThis = Context ? Context->AnimViewportToolBar.Pin().Get() : nullptr;
{
FToolMenuSection& Section = InSubMenu->AddSection("BonesAndSockets", LOCTEXT("CharacterMenu_BonesAndSocketsLabel", "Show"));
Section.AddMenuEntry(FAnimViewportShowCommands::Get().ShowSockets);
Section.AddMenuEntry(FAnimViewportShowCommands::Get().ShowAttributes);
Section.AddMenuEntry(FAnimViewportShowCommands::Get().ShowBoneNames);
Section.AddMenuEntry(FAnimViewportShowCommands::Get().ShowBoneColors);
}
{
FToolMenuSection& Section = InSubMenu->AddSection("AnimViewportPreviewHierarchyBoneDraw", LOCTEXT("CharacterMenu_Actions_BoneDrawing", "Bone Drawing"));
if (ContextThis)
{
TSharedPtr<SWidget> BoneSizeWidget = SNew(UE::AnimationEditor::SBoneDrawSizeSetting).AnimEditorViewport(ContextThis->Viewport);
Section.AddEntry(FToolMenuEntry::InitWidget(TEXT("BoneDrawSize"), BoneSizeWidget.ToSharedRef(), LOCTEXT("CharacterMenu_Actions_BoneDrawSize", "Bone Draw Size:")));
}
Section.AddMenuEntry(FAnimViewportShowCommands::Get().ShowBoneDrawAll);
Section.AddMenuEntry(FAnimViewportShowCommands::Get().ShowBoneDrawSelected);
Section.AddMenuEntry(FAnimViewportShowCommands::Get().ShowBoneDrawSelectedAndParents);
Section.AddMenuEntry(FAnimViewportShowCommands::Get().ShowBoneDrawSelectedAndChildren);
Section.AddMenuEntry(FAnimViewportShowCommands::Get().ShowBoneDrawSelectedAndParentsAndChildren);
Section.AddMenuEntry(FAnimViewportShowCommands::Get().ShowBoneDrawNone);
}
})
);
Section.AddDynamicEntry("ClothingSubMenu", FNewToolMenuSectionDelegate::CreateLambda([](FToolMenuSection& InSection)
{
UAnimViewportToolBarToolMenuContext* Context = InSection.FindContext<UAnimViewportToolBarToolMenuContext>();
const SAnimViewportToolBar* ContextThis = Context ? Context->AnimViewportToolBar.Pin().Get() : nullptr;
UDebugSkelMeshComponent* PreviewComp = ContextThis && ContextThis->Viewport.IsValid() ? ContextThis->Viewport.Pin()->GetPreviewScene()->GetPreviewMeshComponent() : nullptr;
if (PreviewComp && GetDefault<UPersonaOptions>()->bExposeClothingSceneElementMenu)
{
constexpr bool bInOpenSubMenuOnClick = false;
constexpr bool bShouldCloseWindowAfterMenuSelection = false;
InSection.AddSubMenu(TEXT("ClothingSubMenu"),
LOCTEXT("CharacterMenu_ClothingSubMenu", "Clothing"),
LOCTEXT("CharacterMenu_ClothingSubMenuToolTip", "Options relating to clothing"),
FNewToolMenuChoice(FNewMenuDelegate::CreateRaw(const_cast<SAnimViewportToolBar *>(ContextThis), &SAnimViewportToolBar::FillCharacterClothingMenu)),
bInOpenSubMenuOnClick, TAttribute<FSlateIcon>(), bShouldCloseWindowAfterMenuSelection);
}
}));
Section.AddSubMenu(TEXT("AudioSubMenu"),
LOCTEXT("CharacterMenu_AudioSubMenu", "Audio"),
LOCTEXT("CharacterMenu_AudioSubMenuToolTip", "Audio options"),
FNewToolMenuDelegate::CreateLambda([](UToolMenu* InSubMenu)
{
FToolMenuSection& Section = InSubMenu->AddSection("AnimViewportAudio", LOCTEXT("CharacterMenu_Audio", "Audio"));
Section.AddMenuEntry(FAnimViewportShowCommands::Get().MuteAudio);
Section.AddMenuEntry(FAnimViewportShowCommands::Get().UseAudioAttenuation);
}));
Section.AddDynamicEntry("AdvancedSubMenu", FNewToolMenuSectionDelegate::CreateLambda([](FToolMenuSection& InSection)
{
UAnimViewportToolBarToolMenuContext* Context = InSection.FindContext<UAnimViewportToolBarToolMenuContext>();
const SAnimViewportToolBar* ContextThis = Context ? Context->AnimViewportToolBar.Pin().Get() : nullptr;
if (ContextThis)
{
InSection.AddSubMenu(TEXT("AdvancedSubMenu"),
LOCTEXT("CharacterMenu_AdvancedSubMenu", "Advanced"),
LOCTEXT("CharacterMenu_AdvancedSubMenuToolTip", "Advanced options"),
FNewToolMenuChoice(FNewMenuDelegate::CreateRaw(ContextThis, &SAnimViewportToolBar::FillCharacterAdvancedMenu)));
}
}));
Section.AddDynamicEntry("Timecode", FNewToolMenuSectionDelegate::CreateLambda([](FToolMenuSection& InSection)
{
UAnimViewportToolBarToolMenuContext* Context = InSection.FindContext<UAnimViewportToolBarToolMenuContext>();
const SAnimViewportToolBar* ContextThis = Context ? Context->AnimViewportToolBar.Pin().Get() : nullptr;
if (ContextThis)
{
InSection.AddSubMenu(TEXT("TimecodeSubMenu"),
LOCTEXT("CharacterMenu_TimecodeSubMenu", "Timecode"),
LOCTEXT("CharacterMenu_TimecodeSubMenuToolTip", "Timecode options"),
FNewToolMenuChoice(FNewMenuDelegate::CreateRaw(ContextThis, &SAnimViewportToolBar::FillCharacterTimecodeMenu)));
}
}));
}
}
TSharedPtr<FExtender> MenuExtender = FExtender::Combine(Extenders);
TSharedPtr<SAnimationEditorViewportTabBody> PinnedViewport = Viewport.Pin();
FToolMenuContext MenuContext(PinnedViewport->GetCommandList(), MenuExtender);
PinnedViewport->GetAssetEditorToolkit()->InitToolMenuContext(MenuContext);
UAnimViewportToolBarToolMenuContext* AnimViewportContext = NewObject<UAnimViewportToolBarToolMenuContext>();
AnimViewportContext->AnimViewportToolBar = SharedThis(this);
MenuContext.AddObject(AnimViewportContext);
return UToolMenus::Get()->GenerateWidget(MenuName, MenuContext);
}
void SAnimViewportToolBar::FillCharacterTimecodeMenu(FMenuBuilder& MenuBuilder) const
{
const FAnimViewportShowCommands& Actions = FAnimViewportShowCommands::Get();
MenuBuilder.BeginSection("Timecode", LOCTEXT("Timecode_Label", "Timecode"));
{
MenuBuilder.AddMenuEntry( Actions.ShowTimecode );
}
MenuBuilder.EndSection();
}
void SAnimViewportToolBar::FillCharacterAdvancedMenu(FMenuBuilder& MenuBuilder) const
{
const FAnimViewportShowCommands& Actions = FAnimViewportShowCommands::Get();
// Draw UVs
MenuBuilder.BeginSection("UVVisualization", LOCTEXT("UVVisualization_Label", "UV Visualization"));
{
MenuBuilder.AddWidget(Viewport.Pin()->UVChannelCombo.ToSharedRef(), FText());
}
MenuBuilder.EndSection();
MenuBuilder.BeginSection("Skinning", LOCTEXT("Skinning_Label", "Skinning"));
{
MenuBuilder.AddMenuEntry(FAnimViewportMenuCommands::Get().SetCPUSkinning);
}
MenuBuilder.EndSection();
MenuBuilder.BeginSection("ShowVertex", LOCTEXT("ShowVertex_Label", "Vertex Normal Visualization"));
{
// Vertex debug flags
MenuBuilder.AddMenuEntry(FAnimViewportMenuCommands::Get().SetShowNormals);
MenuBuilder.AddMenuEntry(FAnimViewportMenuCommands::Get().SetShowTangents);
MenuBuilder.AddMenuEntry(FAnimViewportMenuCommands::Get().SetShowBinormals);
}
MenuBuilder.EndSection();
MenuBuilder.BeginSection("AnimViewportPreviewHierarchyLocalAxes", LOCTEXT("ShowMenu_Actions_HierarchyAxes", "Hierarchy Local Axes") );
{
MenuBuilder.AddMenuEntry( Actions.ShowLocalAxesAll );
MenuBuilder.AddMenuEntry( Actions.ShowLocalAxesSelected );
MenuBuilder.AddMenuEntry( Actions.ShowLocalAxesNone );
}
MenuBuilder.EndSection();
}
void SAnimViewportToolBar::FillCharacterMirrorMenu(FMenuBuilder& MenuBuilder) const
{
FAssetPickerConfig AssetPickerConfig;
UDebugSkelMeshComponent* PreviewComp = Viewport.Pin()->GetPreviewScene()->GetPreviewMeshComponent();
USkeletalMesh* Mesh = PreviewComp->GetSkeletalMeshAsset();
UAnimPreviewInstance* PreviewInstance = PreviewComp->PreviewInstance;
if (Mesh && PreviewInstance)
{
USkeleton* Skeleton = Mesh->GetSkeleton();
AssetPickerConfig.Filter.ClassPaths.Add(UMirrorDataTable::StaticClass()->GetClassPathName());
AssetPickerConfig.Filter.bRecursiveClasses = false;
AssetPickerConfig.bAllowNullSelection = true;
AssetPickerConfig.OnShouldFilterAsset = FOnShouldFilterAsset::CreateUObject(Skeleton, &USkeleton::ShouldFilterAsset, TEXT("Skeleton"));
AssetPickerConfig.InitialAssetSelection = FAssetData(PreviewInstance->GetMirrorDataTable());
AssetPickerConfig.OnAssetSelected = FOnAssetSelected::CreateRaw(const_cast<SAnimViewportToolBar*>(this), &SAnimViewportToolBar::OnMirrorDataTableSelected);
AssetPickerConfig.InitialAssetViewType = EAssetViewType::List;
AssetPickerConfig.ThumbnailScale = 0.1f;
AssetPickerConfig.bAddFilterUI = false;
FContentBrowserModule& ContentBrowserModule = FModuleManager::Get().LoadModuleChecked<FContentBrowserModule>(TEXT("ContentBrowser"));
MenuBuilder.AddWidget(
ContentBrowserModule.Get().CreateAssetPicker(AssetPickerConfig),
FText::GetEmpty()
);
}
}
void SAnimViewportToolBar::OnMirrorDataTableSelected(const FAssetData& SelectedMirrorTableData)
{
UMirrorDataTable* MirrorDataTable = Cast<UMirrorDataTable>(SelectedMirrorTableData.GetAsset());
if (Viewport.Pin().IsValid())
{
UDebugSkelMeshComponent* PreviewComp = Viewport.Pin()->GetPreviewScene()->GetPreviewMeshComponent();
USkeletalMesh* Mesh = PreviewComp->GetSkeletalMeshAsset();
UAnimPreviewInstance* PreviewInstance = PreviewComp->PreviewInstance;
if (Mesh && PreviewInstance)
{
PreviewInstance->SetMirrorDataTable(MirrorDataTable);
PreviewComp->OnMirrorDataTableChanged();
}
}
}
void SAnimViewportToolBar::FillCharacterClothingMenu(FMenuBuilder& MenuBuilder)
{
const FAnimViewportShowCommands& Actions = FAnimViewportShowCommands::Get();
MenuBuilder.BeginSection("ClothPreview", LOCTEXT("ClothPreview_Label", "Simulation"));
{
MenuBuilder.AddMenuEntry(Actions.EnableClothSimulation);
MenuBuilder.AddMenuEntry(Actions.ResetClothSimulation);
TSharedPtr<SWidget> WindWidget = SNew(UE::AnimationEditor::SClothWindSettings).AnimEditorViewport(Viewport);
MenuBuilder.AddWidget(WindWidget.ToSharedRef(), LOCTEXT("ClothPreview_WindStrength", "Wind Strength:"));
TSharedPtr<SWidget> GravityWidget = SNew(UE::AnimationEditor::SGravitySettings).AnimEditorViewport(Viewport);
MenuBuilder.AddWidget(GravityWidget.ToSharedRef(), LOCTEXT("ClothPreview_GravityScale", "Gravity Scale:"));
MenuBuilder.AddMenuEntry(Actions.EnableCollisionWithAttachedClothChildren);
MenuBuilder.AddMenuEntry(Actions.PauseClothWithAnim);
}
MenuBuilder.EndSection();
MenuBuilder.BeginSection("ClothAdditionalVisualization", LOCTEXT("ClothAdditionalVisualization_Label", "Sections Display Mode"));
{
MenuBuilder.AddMenuEntry(Actions.ShowAllSections);
MenuBuilder.AddMenuEntry(Actions.ShowOnlyClothSections);
MenuBuilder.AddMenuEntry(Actions.HideOnlyClothSections);
}
MenuBuilder.EndSection();
// Call into the clothing editor module to customize the menu (this is mainly for debug visualizations and sim-specific options)
TSharedPtr<SAnimationEditorViewportTabBody> SharedViewport = Viewport.Pin();
if (SharedViewport.IsValid())
{
if (const TSharedPtr<FAnimationViewportClient>& AnimationViewportClient = SharedViewport->GetAnimationViewportClient())
{
TSharedRef<IPersonaPreviewScene> PreviewScene = AnimationViewportClient->GetPreviewScene();
if (UDebugSkelMeshComponent* PreviewComponent = PreviewScene->GetPreviewMeshComponent())
{
if (PreviewComponent->ClothingSimulationFactory) // The cloth plugin could be disabled, and the factory would be null in this case
{
FClothingSystemEditorInterfaceModule& ClothingEditorModule = FModuleManager::LoadModuleChecked<FClothingSystemEditorInterfaceModule>(TEXT("ClothingSystemEditorInterface"));
if (ISimulationEditorExtender* Extender = ClothingEditorModule.GetSimulationEditorExtender(PreviewComponent->ClothingSimulationFactory->GetFName()))
{
Extender->ExtendViewportShowMenu(MenuBuilder, PreviewScene);
}
}
}
}
}
}
TSharedRef<SWidget> SAnimViewportToolBar::GenerateShowMenu() const
{
if (TSharedPtr<SAnimationEditorViewportTabBody> ViewportPinned = Viewport.Pin())
{
constexpr bool bShowViewportStatsToggle = false;
return UE::AnimationEditor::CreateShowMenuWidget(
ViewportPinned->GetViewportWidget().ToSharedRef(), Extenders, bShowViewportStatsToggle
);
}
return SNullWidget::NullWidget;
}
FText SAnimViewportToolBar::GetLODMenuLabel() const
{
return UE::AnimationEditor::GetLODMenuLabel(Viewport);
}
TSharedRef<SWidget> SAnimViewportToolBar::GenerateLODMenu() const
{
return UE::AnimationEditor::GenerateLODMenuWidget(Viewport);
}
TSharedRef<SWidget> SAnimViewportToolBar::GenerateViewportTypeMenu() const
{
TSharedPtr<FExtender> MenuExtender = FExtender::Combine(Extenders);
const bool bInShouldCloseWindowAfterMenuSelection = true;
FMenuBuilder InMenuBuilder(bInShouldCloseWindowAfterMenuSelection, CommandList, MenuExtender);
InMenuBuilder.SetStyle(&FAppStyle::Get(), "Menu");
InMenuBuilder.PushCommandList(CommandList.ToSharedRef());
InMenuBuilder.PushExtender(MenuExtender.ToSharedRef());
// Camera types
InMenuBuilder.AddMenuEntry(FEditorViewportCommands::Get().Perspective);
InMenuBuilder.BeginSection("LevelViewportCameraType_Ortho", LOCTEXT("CameraTypeHeader_Ortho", "Orthographic"));
InMenuBuilder.AddMenuEntry(FEditorViewportCommands::Get().Top);
InMenuBuilder.AddMenuEntry(FEditorViewportCommands::Get().Bottom);
InMenuBuilder.AddMenuEntry(FEditorViewportCommands::Get().Left);
InMenuBuilder.AddMenuEntry(FEditorViewportCommands::Get().Right);
InMenuBuilder.AddMenuEntry(FEditorViewportCommands::Get().Front);
InMenuBuilder.AddMenuEntry(FEditorViewportCommands::Get().Back);
InMenuBuilder.EndSection();
InMenuBuilder.PopCommandList();
InMenuBuilder.PopExtender();
return InMenuBuilder.MakeWidget();
}
TSharedRef<SWidget> SAnimViewportToolBar::GeneratePlaybackMenu() const
{
if (const TSharedPtr<SAnimationEditorViewportTabBody>& ViewportTabPinned = Viewport.Pin())
{
return UE::AnimationEditor::GeneratePlaybackMenu(ViewportTabPinned->GetPreviewScene(), Extenders);
}
return SNullWidget::NullWidget;
}
void SAnimViewportToolBar::GenerateTurnTableMenu(FMenuBuilder& MenuBuilder) const
{
MenuBuilder.AddWidget(
UE::AnimationEditor::GenerateTurnTableMenu(Viewport),
FText(),
false,
true,
LOCTEXT("TurnTableTooltip", "Set up auto-rotation of preview.")
);
}
FSlateColor SAnimViewportToolBar::GetFontColor() const
{
const UAssetViewerSettings* Settings = UAssetViewerSettings::Get();
const UEditorPerProjectUserSettings* PerProjectUserSettings = GetDefault<UEditorPerProjectUserSettings>();
const int32 ProfileIndex = Settings->Profiles.IsValidIndex(PerProjectUserSettings->AssetViewerProfileIndex) ? PerProjectUserSettings->AssetViewerProfileIndex : 0;
ensureMsgf(Settings->Profiles.IsValidIndex(PerProjectUserSettings->AssetViewerProfileIndex), TEXT("Invalid default settings pointer or current profile index"));
FLinearColor FontColor;
if (Settings->Profiles[ProfileIndex].bShowEnvironment)
{
FontColor = FLinearColor::White;
}
else
{
FLinearColor Color = Settings->Profiles[ProfileIndex].EnvironmentColor * Settings->Profiles[ProfileIndex].EnvironmentIntensity;
// see if it's dark, if V is less than 0.2
if (Color.B < 0.3f )
{
FontColor = FLinearColor::White;
}
else
{
FontColor = FLinearColor::Black;
}
}
return FontColor;
}
FText SAnimViewportToolBar::GetPlaybackMenuLabel() const
{
FText Label = LOCTEXT("PlaybackError", "Error");
if (const TSharedPtr<SAnimationEditorViewportTabBody>& ViewportTabPinned = Viewport.Pin())
{
return UE::AnimationEditor::GetPlaybackMenuLabel(ViewportTabPinned->GetPreviewScene());
}
return Label;
}
FText SAnimViewportToolBar::GetCameraMenuLabel() const
{
TSharedPtr< SAnimationEditorViewportTabBody > PinnedViewport(Viewport.Pin());
if( PinnedViewport.IsValid() )
{
return UE::UnrealEd::GetCameraSubmenuLabelFromViewportType(PinnedViewport->GetLevelViewportClient().ViewportType);
}
return LOCTEXT("Viewport_Default", "Camera");
}
const FSlateBrush* SAnimViewportToolBar::GetCameraMenuLabelIcon() const
{
TSharedPtr< SAnimationEditorViewportTabBody > PinnedViewport( Viewport.Pin() );
if( PinnedViewport.IsValid() )
{
return GetCameraMenuLabelIconFromViewportType(PinnedViewport->GetLevelViewportClient().ViewportType );
}
return FAppStyle::Get().GetBrush("NoBrush");
}
TOptional<float> SAnimViewportToolBar::OnGetFOVValue() const
{
if(Viewport.IsValid())
{
return Viewport.Pin()->GetLevelViewportClient().ViewFOV;
}
return 0.0f;
}
void SAnimViewportToolBar::OnFOVValueChanged( float NewValue )
{
FEditorViewportClient& ViewportClient = Viewport.Pin()->GetLevelViewportClient();
ViewportClient.FOVAngle = NewValue;
FAnimationViewportClient& AnimViewportClient = (FAnimationViewportClient&)(ViewportClient);
AnimViewportClient.ConfigOption->SetViewFOV(AnimViewportClient.GetAssetEditorToolkit()->GetEditorName(), NewValue, AnimViewportClient.GetViewportIndex());
ViewportClient.ViewFOV = NewValue;
ViewportClient.Invalidate();
if (TSharedPtr<SAnimationEditorViewportTabBody> ViewportTabPinned = Viewport.Pin())
{
if (TSharedPtr<IPinnedCommandList> CommandsPinned = ViewportTabPinned->GetPinnedCommands())
{
CommandsPinned->AddCustomWidget(TEXT("FOVWidget"));
}
}
}
void SAnimViewportToolBar::OnFOVValueCommitted( float NewValue, ETextCommit::Type CommitInfo )
{
//OnFOVValueChanged will be called... nothing needed here.
}
void SAnimViewportToolBar::OnCamSpeedChanged(int32 NewValue)
{
FEditorViewportClient& ViewportClient = Viewport.Pin()->GetLevelViewportClient();
FAnimationViewportClient& AnimViewportClient = (FAnimationViewportClient&)(ViewportClient);
AnimViewportClient.ConfigOption->SetCameraSpeed(AnimViewportClient.GetAssetEditorToolkit()->GetEditorName(), NewValue, AnimViewportClient.GetViewportIndex());
}
void SAnimViewportToolBar::OnCamSpeedScalarChanged(float NewValue)
{
FEditorViewportClient& ViewportClient = Viewport.Pin()->GetLevelViewportClient();
FAnimationViewportClient& AnimViewportClient = (FAnimationViewportClient&)(ViewportClient);
AnimViewportClient.ConfigOption->SetCameraSpeedScalar(AnimViewportClient.GetAssetEditorToolkit()->GetEditorName(), NewValue, AnimViewportClient.GetViewportIndex());
}
void SAnimViewportToolBar::AddMenuExtender(FName MenuToExtend, FMenuExtensionDelegate MenuBuilderDelegate)
{
TSharedRef<FExtender> Extender(new FExtender());
Extender->AddMenuExtension(
MenuToExtend,
EExtensionHook::After,
CommandList,
MenuBuilderDelegate
);
Extenders.Add(Extender);
}
TSharedRef<FExtender> SAnimViewportToolBar::GetViewMenuExtender(TSharedPtr<class SEditorViewport> InRealViewport)
{
TSharedRef<FExtender> Extender(new FExtender());
Extender->AddMenuExtension(
TEXT("ViewMode"),
EExtensionHook::After,
InRealViewport->GetCommandList(),
FMenuExtensionDelegate::CreateLambda([this](FMenuBuilder& InMenuBuilder)
{
InMenuBuilder.AddSubMenu(
LOCTEXT("VisualizeBufferViewModeDisplayName", "Buffer Visualization"),
LOCTEXT("BufferVisualizationMenu_ToolTip", "Select a mode for buffer visualization"),
FNewMenuDelegate::CreateStatic(&FBufferVisualizationMenuCommands::BuildVisualisationSubMenu),
FUIAction(
FExecuteAction(),
FCanExecuteAction(),
FIsActionChecked::CreateLambda([this]()
{
const TSharedPtr<SAnimationEditorViewportTabBody> ViewportPtr = Viewport.Pin();
if (ViewportPtr.IsValid())
{
const FEditorViewportClient& ViewportClient = ViewportPtr->GetViewportClient();
return ViewportClient.IsViewModeEnabled(VMI_VisualizeBuffer);
}
return false;
})
),
"VisualizeBufferViewMode",
EUserInterfaceActionType::RadioButton,
/* bInOpenSubMenuOnClick = */ false,
FSlateIcon(FAppStyle::GetAppStyleSetName(), "EditorViewport.VisualizeBufferMode")
);
}));
return Extender;
}
#undef LOCTEXT_NAMESPACE