EM_Task/UnrealEd/Private/EditorModeManager.cpp
Boshuang Zhao 5144a49c9b add
2026-02-13 16:18:33 +08:00

1754 lines
50 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "EditorModeManager.h"
#include "Engine/Selection.h"
#include "Misc/MessageDialog.h"
#include "Classes/EditorStyleSettings.h"
#include "Editor/EditorPerProjectUserSettings.h"
#include "Misc/ConfigCacheIni.h"
#include "GameFramework/WorldSettings.h"
#include "LevelEditorViewport.h"
#include "EditorModeRegistry.h"
#include "EditorModes.h"
#include "Engine/BookMark.h"
#include "EditorSupportDelegates.h"
#include "EdMode.h"
#include "Toolkits/IToolkitHost.h"
#include "Framework/Notifications/NotificationManager.h"
#include "Widgets/Notifications/SNotificationList.h"
#include "Widgets/Input/SButton.h"
#include "Engine/LevelStreaming.h"
#include "EditorWorldExtension.h"
#include "ViewportWorldInteraction.h"
#include "Editor/EditorEngine.h"
#include "UnrealEdGlobals.h"
#include "Editor/UnrealEdEngine.h"
#include "Bookmarks/IBookmarkTypeTools.h"
#include "Widgets/Docking/SDockTab.h"
#include "Widgets/Layout/SWidgetSwitcher.h"
#include "EditorStyleSet.h"
#include "Framework/Commands/UICommandList.h"
#include "Framework/MultiBox/MultiBoxBuilder.h"
#include "Toolkits/BaseToolkit.h"
#include "Subsystems/AssetEditorSubsystem.h"
#include "Subsystems/BrushEditingSubsystem.h"
#include "Tools/UEdMode.h"
#include "Widgets/Images/SImage.h"
#include "InputRouter.h"
#include "InteractiveGizmoManager.h"
/*------------------------------------------------------------------------------
FEditorModeTools.
The master class that handles tracking of the current mode.
------------------------------------------------------------------------------*/
const FName FEditorModeTools::EditorModeToolbarTabName = TEXT("EditorModeToolbar");
FEditorModeTools::FEditorModeTools()
: PivotShown(false), Snapping(false), SnappedActor(false), CachedLocation(ForceInitToZero), PivotLocation(ForceInitToZero), SnappedLocation(ForceInitToZero), GridBase(ForceInitToZero), TranslateRotateXAxisAngle(0.0f), TranslateRotate2DAngle(0.0f), DefaultModeIDs(), WidgetMode(FWidget::WM_None), OverrideWidgetMode(FWidget::WM_None), bShowWidget(true), bHideViewportUI(false), bSelectionHasSceneComponent(false), WidgetScale(1.0f), CoordSystem(COORD_World), bIsTracking(false)
{
DefaultModeIDs.Add(FBuiltinEditorModes::EM_Default);
// Load the last used settings
LoadConfig();
// Register our callback for actor selection changes
USelection::SelectNoneEvent.AddRaw(this, &FEditorModeTools::OnEditorSelectNone);
USelection::SelectionChangedEvent.AddRaw(this, &FEditorModeTools::OnEditorSelectionChanged);
USelection::SelectObjectEvent.AddRaw(this, &FEditorModeTools::OnEditorSelectionChanged);
if (GEditor)
{
// Register our callback for undo/redo
GEditor->RegisterForUndo(this);
// This binding ensures the mode is destroyed if the type is unregistered outside of normal shutdown process
GEditor->GetEditorSubsystem<UAssetEditorSubsystem>()->OnEditorModeUnregistered().AddRaw(this, &FEditorModeTools::OnModeUnregistered);
}
}
FEditorModeTools::~FEditorModeTools()
{
if (GEditor)
{
GEditor->UnregisterForUndo(this);
GEditor->GetEditorSubsystem<UAssetEditorSubsystem>()->OnEditorModeUnregistered().RemoveAll(this);
}
DeactivateAllModes();
RecycledScriptableModes.Empty();
USelection::SelectionChangedEvent.RemoveAll(this);
USelection::SelectNoneEvent.RemoveAll(this);
USelection::SelectObjectEvent.RemoveAll(this);
}
void FEditorModeTools::LoadConfig(void)
{
GConfig->GetBool(TEXT("FEditorModeTools"), TEXT("ShowWidget"), bShowWidget,
GEditorPerProjectIni);
const bool bGetRawValue = true;
int32 Bogus = (int32)GetCoordSystem(bGetRawValue);
GConfig->GetInt(TEXT("FEditorModeTools"), TEXT("CoordSystem"), Bogus,
GEditorPerProjectIni);
SetCoordSystem((ECoordSystem)Bogus);
LoadWidgetSettings();
}
void FEditorModeTools::SaveConfig(void)
{
GConfig->SetBool(TEXT("FEditorModeTools"), TEXT("ShowWidget"), bShowWidget, GEditorPerProjectIni);
const bool bGetRawValue = true;
GConfig->SetInt(TEXT("FEditorModeTools"), TEXT("CoordSystem"), (int32)GetCoordSystem(bGetRawValue), GEditorPerProjectIni);
SaveWidgetSettings();
}
TSharedPtr<class IToolkitHost> FEditorModeTools::GetToolkitHost() const
{
TSharedPtr<class IToolkitHost> Result = ToolkitHost.Pin();
check(ToolkitHost.IsValid());
return Result;
}
bool FEditorModeTools::HasToolkitHost() const
{
return ToolkitHost.Pin().IsValid();
}
void FEditorModeTools::SetToolkitHost(TSharedRef<class IToolkitHost> InHost)
{
checkf(!ToolkitHost.IsValid(), TEXT("SetToolkitHost can only be called once"));
ToolkitHost = InHost;
}
USelection* FEditorModeTools::GetSelectedActors() const
{
return GEditor->GetSelectedActors();
}
USelection* FEditorModeTools::GetSelectedObjects() const
{
return GEditor->GetSelectedObjects();
}
USelection* FEditorModeTools::GetSelectedComponents() const
{
return GEditor->GetSelectedComponents();
}
UWorld* FEditorModeTools::GetWorld() const
{
// When in 'Simulate' mode, the editor mode tools will actually interact with the PIE world
if (GEditor->bIsSimulatingInEditor)
{
return GEditor->GetPIEWorldContext()->World();
}
else
{
return GEditor->GetEditorWorldContext().World();
}
}
FEditorViewportClient* FEditorModeTools::GetHoveredViewportClient() const
{
// This is our best effort right now. However this is somewhat incorrect as if you Hover
// on other Viewports they get mouse events, but this value stays on the Focused viewport.
// Not sure what to do about this right now.
return HoveredViewportClient;
}
FEditorViewportClient* FEditorModeTools::GetFocusedViewportClient() const
{
// This is our best effort right now. However this is somewhat incorrect as if you Hover
// on other Viewports they get mouse events, but this value stays on the Focused viewport.
// Not sure what to do about this right now.
return FocusedViewportClient;
}
bool FEditorModeTools::SelectionHasSceneComponent() const
{
return bSelectionHasSceneComponent;
}
bool FEditorModeTools::IsSelectionAllowed(AActor* InActor, const bool bInSelected) const
{
bool bSelectionAllowed = (ActiveScriptableModes.Num() == 0);
for (const UEdMode* Mode: ActiveScriptableModes)
{
bSelectionAllowed |= Mode->IsSelectionAllowed(InActor, bInSelected);
}
return bSelectionAllowed;
}
bool FEditorModeTools::IsSelectionHandled(AActor* InActor, const bool bInSelected) const
{
bool bSelectionHandled = false;
for (UEdMode* Mode: ActiveScriptableModes)
{
bSelectionHandled |= Mode->Select(InActor, bInSelected);
}
return bSelectionHandled;
}
bool FEditorModeTools::ProcessEditDuplicate()
{
bool bHandled = false;
for (UEdMode* Mode: ActiveScriptableModes)
{
bHandled = Mode->ProcessEditDuplicate();
}
return bHandled;
}
bool FEditorModeTools::ProcessEditDelete()
{
bool bHandled = false;
for (UEdMode* Mode: ActiveScriptableModes)
{
bHandled = Mode->ProcessEditDelete();
}
return bHandled;
}
bool FEditorModeTools::ProcessEditCut()
{
for (UEdMode* Mode: ActiveScriptableModes)
{
if (Mode->ProcessEditCut())
{
return true;
}
}
return false;
}
bool FEditorModeTools::ProcessEditCopy()
{
for (UEdMode* Mode: ActiveScriptableModes)
{
if (Mode->ProcessEditCopy())
{
return true;
}
}
return false;
}
bool FEditorModeTools::ProcessEditPaste()
{
for (UEdMode* Mode: ActiveScriptableModes)
{
if (Mode->ProcessEditPaste())
{
return true;
}
}
return false;
}
EEditAction::Type FEditorModeTools::GetActionEditDuplicate()
{
for (UEdMode* Mode: ActiveScriptableModes)
{
const EEditAction::Type EditAction = Mode->GetActionEditDuplicate();
if (EditAction == EEditAction::Process || EditAction == EEditAction::Halt)
{
return EditAction;
}
}
return EEditAction::Skip;
}
EEditAction::Type FEditorModeTools::GetActionEditDelete()
{
for (UEdMode* Mode: ActiveScriptableModes)
{
const EEditAction::Type EditAction = Mode->GetActionEditDelete();
if (EditAction == EEditAction::Process || EditAction == EEditAction::Halt)
{
return EditAction;
}
}
return EEditAction::Skip;
}
EEditAction::Type FEditorModeTools::GetActionEditCut()
{
for (UEdMode* Mode: ActiveScriptableModes)
{
const EEditAction::Type EditAction = Mode->GetActionEditCut();
if (EditAction == EEditAction::Process || EditAction == EEditAction::Halt)
{
return EditAction;
}
}
return EEditAction::Skip;
}
EEditAction::Type FEditorModeTools::GetActionEditCopy()
{
for (UEdMode* Mode: ActiveScriptableModes)
{
const EEditAction::Type EditAction = Mode->GetActionEditCopy();
if (EditAction == EEditAction::Process || EditAction == EEditAction::Halt)
{
return EditAction;
}
}
return EEditAction::Skip;
}
EEditAction::Type FEditorModeTools::GetActionEditPaste()
{
for (UEdMode* Mode: ActiveScriptableModes)
{
const EEditAction::Type EditAction = Mode->GetActionEditPaste();
if (EditAction == EEditAction::Process || EditAction == EEditAction::Halt)
{
return EditAction;
}
}
return EEditAction::Skip;
}
void FEditorModeTools::DeactivateOtherVisibleModes(FEditorModeID InMode)
{
TArray<UEdMode*> TempModes(ActiveScriptableModes);
for (const UEdMode* Mode: TempModes)
{
if (Mode->GetID() != InMode && Mode->GetModeInfo().bVisible)
{
DeactivateMode(Mode->GetID());
}
}
}
bool FEditorModeTools::IsSnapRotationEnabled() const
{
for (UEdMode* Mode: ActiveScriptableModes)
{
if (Mode->IsSnapRotationEnabled())
{
return true;
}
}
return false;
}
bool FEditorModeTools::SnapRotatorToGridOverride(FRotator& InRotation) const
{
for (UEdMode* Mode: ActiveScriptableModes)
{
if (Mode->SnapRotatorToGridOverride(InRotation))
{
return true;
}
}
return false;
}
void FEditorModeTools::ActorsDuplicatedNotify(TArray<AActor*>& InPreDuplicateSelection, TArray<AActor*>& InPostDuplicateSelection, const bool bOffsetLocations)
{
for (UEdMode* Mode: ActiveScriptableModes)
{
// Tell the tools about the duplication
Mode->ActorsDuplicatedNotify(InPreDuplicateSelection, InPostDuplicateSelection, bOffsetLocations);
}
}
void FEditorModeTools::ActorMoveNotify()
{
for (UEdMode* Mode: ActiveScriptableModes)
{
// Also notify the current editing modes if they are interested.
Mode->ActorMoveNotify();
}
}
void FEditorModeTools::ActorSelectionChangeNotify()
{
for (UEdMode* Mode: ActiveScriptableModes)
{
Mode->ActorSelectionChangeNotify();
}
}
void FEditorModeTools::ActorPropChangeNotify()
{
for (UEdMode* Mode: ActiveScriptableModes)
{
Mode->ActorPropChangeNotify();
}
}
void FEditorModeTools::UpdateInternalData()
{
for (UEdMode* Mode: ActiveScriptableModes)
{
Mode->UpdateInternalData();
}
}
bool FEditorModeTools::IsOnlyVisibleActiveMode(FEditorModeID InMode) const
{
// Only return true if this is the *only* active mode
for (const UEdMode* Mode: ActiveScriptableModes)
{
if (Mode->GetModeInfo().bVisible && Mode->GetID() != InMode)
{
return false;
}
}
return true;
}
void FEditorModeTools::OnEditorSelectionChanged(UObject* NewSelection)
{
if (NewSelection == GetSelectedActors())
{
// when actors are selected check if there is at least one component selected and cache that off
// Editor modes use this primarily to determine of transform gizmos should be drawn.
// Performing this check each frame with lots of actors is expensive so only do this when selection changes
bSelectionHasSceneComponent = false;
for (FSelectionIterator It(*GetSelectedActors()); It; ++It)
{
AActor* Actor = Cast<AActor>(*It);
if (Actor != nullptr && Actor->FindComponentByClass<USceneComponent>() != nullptr)
{
bSelectionHasSceneComponent = true;
break;
}
}
}
else
{
// If selecting an actor, move the pivot location.
AActor* Actor = Cast<AActor>(NewSelection);
if (Actor != nullptr)
{
if (Actor->IsSelected())
{
SetPivotLocation(Actor->GetActorLocation(), false);
// If this actor wasn't part of the original selection set during pie/sie, clear it now
if (GEditor->ActorsThatWereSelected.Num() > 0)
{
AActor* EditorActor = EditorUtilities::GetEditorWorldCounterpartActor(Actor);
if (!EditorActor || !GEditor->ActorsThatWereSelected.Contains(EditorActor))
{
GEditor->ActorsThatWereSelected.Empty();
}
}
}
else if (GEditor->ActorsThatWereSelected.Num() > 0)
{
// Clear the selection set
GEditor->ActorsThatWereSelected.Empty();
}
}
}
for (const auto& Pair: FEditorModeRegistry::Get().GetFactoryMap())
{
Pair.Value->OnSelectionChanged(*this, NewSelection);
}
}
void FEditorModeTools::OnEditorSelectNone()
{
GEditor->SelectNone(false, true);
GEditor->ActorsThatWereSelected.Empty();
}
void FEditorModeTools::SetPivotLocation(const FVector& Location, const bool bIncGridBase)
{
CachedLocation = PivotLocation = SnappedLocation = Location;
if (bIncGridBase)
{
GridBase = Location;
}
}
ECoordSystem FEditorModeTools::GetCoordSystem(bool bGetRawValue)
{
bool bAligningToActors = false;
if (GEditor->GetEditorWorldExtensionsManager() != nullptr && GetWorld() != nullptr)
{
UEditorWorldExtensionCollection* WorldExtensionCollection = GEditor->GetEditorWorldExtensionsManager()->GetEditorWorldExtensions(GetWorld(), false);
if (WorldExtensionCollection != nullptr)
{
UViewportWorldInteraction* ViewportWorldInteraction = Cast<UViewportWorldInteraction>(WorldExtensionCollection->FindExtension(UViewportWorldInteraction::StaticClass()));
if (ViewportWorldInteraction != nullptr && ViewportWorldInteraction->AreAligningToActors() == true)
{
bAligningToActors = true;
}
}
}
if (!bGetRawValue &&
((GetWidgetMode() == FWidget::WM_Scale) || bAligningToActors))
{
return COORD_Local;
}
else
{
return CoordSystem;
}
}
void FEditorModeTools::SetCoordSystem(ECoordSystem NewCoordSystem)
{
// If we are trying to enter world space but are aligning to actors, turn off aligning to actors
if (GEditor->GetEditorWorldExtensionsManager() != nullptr && GetWorld() != nullptr && NewCoordSystem == COORD_World)
{
UEditorWorldExtensionCollection* WorldExtensionCollection = GEditor->GetEditorWorldExtensionsManager()->GetEditorWorldExtensions(GetWorld(), false);
if (WorldExtensionCollection != nullptr)
{
UViewportWorldInteraction* ViewportWorldInteraction = Cast<UViewportWorldInteraction>(WorldExtensionCollection->FindExtension(UViewportWorldInteraction::StaticClass()));
if (ViewportWorldInteraction != nullptr && ViewportWorldInteraction->AreAligningToActors() == true)
{
if (ViewportWorldInteraction->HasCandidatesSelected())
{
ViewportWorldInteraction->SetSelectionAsCandidates();
}
GUnrealEd->Exec(GetWorld(), TEXT("VI.EnableGuides 0"));
}
}
}
CoordSystem = NewCoordSystem;
BroadcastCoordSystemChanged(NewCoordSystem);
}
void FEditorModeTools::SetDefaultMode(const FEditorModeID DefaultModeID)
{
DefaultModeIDs.Reset();
DefaultModeIDs.Add(DefaultModeID);
}
void FEditorModeTools::AddDefaultMode(const FEditorModeID DefaultModeID)
{
DefaultModeIDs.AddUnique(DefaultModeID);
}
void FEditorModeTools::RemoveDefaultMode(const FEditorModeID DefaultModeID)
{
DefaultModeIDs.RemoveSingle(DefaultModeID);
}
void FEditorModeTools::ActivateDefaultMode()
{
// NOTE: Activating EM_Default will cause ALL default editor modes to be activated (handled specially in ActivateMode())
ActivateMode(FBuiltinEditorModes::EM_Default);
}
void FEditorModeTools::DeactivateScriptableModeAtIndex(int32 InIndex)
{
check(InIndex >= 0 && InIndex < ActiveScriptableModes.Num());
UEdMode* Mode = ActiveScriptableModes[InIndex];
Mode->Exit();
const bool bIsEnteringMode = false;
BroadcastEditorModeIDChanged(Mode->GetID(), bIsEnteringMode);
// Remove the toolbar widget
ActiveToolBarRows.RemoveAll(
[&Mode](FEdModeToolbarRow& Row)
{
return Row.ModeID == Mode->GetID();
});
RebuildModeToolBar();
RecycledScriptableModes.Add(Mode->GetID(), Mode);
ActiveScriptableModes.RemoveAt(InIndex);
}
void FEditorModeTools::OnModeUnregistered(FEditorModeID ModeID)
{
DestroyMode(ModeID);
}
void FEditorModeTools::RebuildModeToolBar()
{
// If the tab or box is not valid the toolbar has not been opened or has been closed by the user
TSharedPtr<SVerticalBox> ModeToolbarBoxPinned = ModeToolbarBox.Pin();
if (ModeToolbarTab.IsValid() && ModeToolbarBoxPinned.IsValid())
{
ModeToolbarBoxPinned->ClearChildren();
TSharedRef<SHorizontalBox> PaletteTabBox = SNew(SHorizontalBox);
TSharedRef<SWidgetSwitcher> PaletteSwitcher = SNew(SWidgetSwitcher);
int32 PaletteCount = ActiveToolBarRows.Num();
if (PaletteCount > 0)
{
for (int32 RowIdx = 0; RowIdx < PaletteCount; ++RowIdx)
{
const FEdModeToolbarRow& Row = ActiveToolBarRows[RowIdx];
if (ensure(Row.ToolbarWidget.IsValid()))
{
TSharedRef<SWidget> PaletteWidget = Row.ToolbarWidget.ToSharedRef();
TSharedPtr<FModeToolkit> RowToolkit;
if (FEdMode* Mode = GetActiveMode(Row.ModeID))
{
RowToolkit = Mode->GetToolkit();
}
else if (UEdMode* ScriptableMode = GetActiveScriptableMode(Row.ModeID))
{
RowToolkit = ScriptableMode->GetToolkit();
}
// Don't show Palette Tabs if there is only one
if (PaletteCount > 1)
{
PaletteTabBox->AddSlot()
.AutoWidth()
.Padding(FMargin(0.f, 1.0f, 1.0f, 0.0f))
[SNew(SCheckBox)
.Style(FEditorStyle::Get(), "ToolPalette.DockingTab")
.OnCheckStateChanged_Lambda([PaletteSwitcher, Row, RowToolkit](const ECheckBoxState)
{
PaletteSwitcher->SetActiveWidget(Row.ToolbarWidget.ToSharedRef());
RowToolkit->OnToolPaletteChanged(Row.PaletteName);
})
.IsChecked_Lambda([PaletteSwitcher, PaletteWidget]() -> ECheckBoxState
{
return PaletteSwitcher->GetActiveWidget() == PaletteWidget ? ECheckBoxState::Checked : ECheckBoxState::Unchecked;
})[SNew(STextBlock).Text(Row.DisplayName)]];
}
PaletteSwitcher->AddSlot()
[PaletteWidget];
}
}
ModeToolbarBoxPinned->AddSlot()
.AutoHeight()
[SNew(SOverlay) + SOverlay::Slot()[SNew(SImage).Image(FEditorStyle::GetBrush("ToolPalette.DockingWell"))]
+ SOverlay::Slot()
[PaletteTabBox]];
ModeToolbarBoxPinned->AddSlot()
.Padding(1.f)
[SNew(SBox)
.HeightOverride(45.f)
[PaletteSwitcher]];
ModeToolbarPaletteSwitcher = PaletteSwitcher;
}
else
{
ModeToolbarTab.Pin()->RequestCloseTab();
}
}
}
void FEditorModeTools::SpawnOrUpdateModeToolbar()
{
if (ShouldShowModeToolbar())
{
if (ModeToolbarTab.IsValid())
{
RebuildModeToolBar();
}
else if (ToolkitHost.IsValid())
{
ToolkitHost.Pin()->GetTabManager()->TryInvokeTab(EditorModeToolbarTabName);
}
}
}
void FEditorModeTools::InvokeToolPaletteTab(FEditorModeID InModeID, FName InPaletteName)
{
if (!ModeToolbarPaletteSwitcher.Pin())
{
return;
}
for (auto Row: ActiveToolBarRows)
{
if (Row.ModeID == InModeID && Row.PaletteName == InPaletteName)
{
TSharedRef<SWidget> PaletteWidget = Row.ToolbarWidget.ToSharedRef();
TSharedPtr<FModeToolkit> RowToolkit;
if (FEdMode* Mode = GetActiveMode(InModeID))
{
RowToolkit = Mode->GetToolkit();
}
else if (UEdMode* ScriptableMode = GetActiveScriptableMode(InModeID))
{
RowToolkit = ScriptableMode->GetToolkit();
}
TSharedPtr<SWidget> ActiveWidget = ModeToolbarPaletteSwitcher.Pin()->GetActiveWidget();
if (RowToolkit && ActiveWidget.Get() != Row.ToolbarWidget.Get())
{
ModeToolbarPaletteSwitcher.Pin()->SetActiveWidget(Row.ToolbarWidget.ToSharedRef());
RowToolkit->OnToolPaletteChanged(Row.PaletteName);
}
break;
}
}
}
void FEditorModeTools::DeactivateMode(FEditorModeID InID)
{
// Find the mode from the ID and exit it.
for (int32 Index = ActiveScriptableModes.Num() - 1; Index >= 0; --Index)
{
auto& Mode = ActiveScriptableModes[Index];
if (Mode->GetID() == InID)
{
DeactivateScriptableModeAtIndex(Index);
break;
}
}
if ((ActiveScriptableModes.Num() == 0))
{
// Ensure the default mode is active if there are no active modes.
ActivateDefaultMode();
}
}
void FEditorModeTools::DeactivateAllModes()
{
for (int32 Index = ActiveScriptableModes.Num() - 1; Index >= 0; --Index)
{
DeactivateScriptableModeAtIndex(Index);
}
}
void FEditorModeTools::DestroyMode(FEditorModeID InID)
{
// Since deactivating the last active mode will cause the default modes to be activated, make sure this mode is removed from defaults.
RemoveDefaultMode(InID);
// Add back the default default mode if we just removed the last valid default.
if (DefaultModeIDs.Num() == 0)
{
AddDefaultMode(FBuiltinEditorModes::EM_Default);
}
// Find the mode from the ID and exit it.
for (int32 Index = ActiveScriptableModes.Num() - 1; Index >= 0; --Index)
{
auto& Mode = ActiveScriptableModes[Index];
if (Mode->GetID() == InID)
{
// Deactivate and destroy
DeactivateScriptableModeAtIndex(Index);
break;
}
}
RecycledScriptableModes.Remove(InID);
}
TSharedRef<SDockTab> FEditorModeTools::MakeModeToolbarTab()
{
TSharedRef<SDockTab> ToolbarTabRef =
SNew(SDockTab)
.Label(NSLOCTEXT("EditorModes", "EditorModesToolbarTitle", "Mode Toolbar"))
.ShouldAutosize(true)
.ContentPadding(0.0f)
.Icon(FEditorStyle::GetBrush("ToolBar.Icon"))
[SAssignNew(ModeToolbarBox, SVerticalBox)];
ModeToolbarTab = ToolbarTabRef;
// Rebuild the toolbar with existing mode tools that may be active
RebuildModeToolBar();
return ToolbarTabRef;
}
bool FEditorModeTools::ShouldShowModeToolbar() const
{
return ActiveToolBarRows.Num() > 0;
}
bool FEditorModeTools::ShouldShowModeToolbox() const
{
for (const UEdMode* Mode: ActiveScriptableModes)
{
if (Mode->GetModeInfo().bVisible && Mode->UsesToolkits())
{
return true;
}
}
return false;
}
void FEditorModeTools::ActivateMode(FEditorModeID InID, bool bToggle)
{
static bool bReentrant = false;
if (!bReentrant)
{
if (InID == FBuiltinEditorModes::EM_Default)
{
bReentrant = true;
for (const FEditorModeID& ModeID: DefaultModeIDs)
{
ActivateMode(ModeID);
}
for (const FEditorModeID& ModeID: DefaultModeIDs)
{
check(IsModeActive(ModeID));
}
bReentrant = false;
return;
}
}
// Check to see if the mode is already active
if (IsModeActive(InID))
{
// The mode is already active toggle it off if we should toggle off already active modes.
if (bToggle)
{
DeactivateMode(InID);
}
// Nothing more to do
return;
}
// Recycle a mode or factory a new one
UEdMode* ScriptableMode = RecycledScriptableModes.FindRef(InID);
if (ScriptableMode)
{
RecycledScriptableModes.Remove(InID);
}
else
{
ScriptableMode = GEditor->GetEditorSubsystem<UAssetEditorSubsystem>()->CreateEditorModeWithToolsOwner(InID, *this);
}
if (!ScriptableMode)
{
UE_LOG(LogEditorModes, Log, TEXT("FEditorModeTools::ActivateMode : Couldn't find mode '%s'."), *InID.ToString());
// Just return and leave the mode list unmodified
return;
}
// Remove anything that isn't compatible with this mode
for (int32 ModeIndex = ActiveScriptableModes.Num() - 1; ModeIndex >= 0; ModeIndex--)
{
const bool bModesAreCompatible = ScriptableMode->IsCompatibleWith(ActiveScriptableModes[ModeIndex]->GetID()) || ActiveScriptableModes[ModeIndex]->IsCompatibleWith(ScriptableMode->GetID());
if (!bModesAreCompatible)
{
DeactivateScriptableModeAtIndex(ModeIndex);
}
}
ActiveScriptableModes.Add(ScriptableMode);
// Enter the new mode
ScriptableMode->Enter();
const bool bIsEnteringMode = true;
BroadcastEditorModeIDChanged(ScriptableMode->GetID(), bIsEnteringMode);
// Ask the mode to build the toolbar.
TSharedPtr<FUICommandList> CommandList;
const TSharedPtr<FModeToolkit> Toolkit = ScriptableMode->GetToolkit();
if (Toolkit.IsValid())
{
CommandList = Toolkit->GetToolkitCommands();
// Also build the toolkit here
int32 PaletteCount = 0;
TArray<FName> PaletteNames;
Toolkit->GetToolPaletteNames(PaletteNames);
for (auto Palette: PaletteNames)
{
FUniformToolBarBuilder ModeToolbarBuilder(CommandList, FMultiBoxCustomization(ScriptableMode->GetModeInfo().ToolbarCustomizationName), TSharedPtr<FExtender>(), false);
ModeToolbarBuilder.SetStyle(&FEditorStyle::Get(), "PaletteToolBar");
Toolkit->BuildToolPalette(Palette, ModeToolbarBuilder);
ActiveToolBarRows.Emplace(ScriptableMode->GetID(), Palette, Toolkit->GetToolPaletteDisplayName(Palette), ModeToolbarBuilder.MakeWidget());
PaletteCount++;
}
if (PaletteCount > 0)
{
SpawnOrUpdateModeToolbar();
}
}
// Update the editor UI
FEditorSupportDelegates::UpdateUI.Broadcast();
}
bool FEditorModeTools::EnsureNotInMode(FEditorModeID ModeID, const FText& ErrorMsg, bool bNotifyUser) const
{
// We're in a 'safe' mode if we're not in the specified mode.
const bool bInASafeMode = !IsModeActive(ModeID);
if (!bInASafeMode && !ErrorMsg.IsEmpty())
{
// Do we want to display this as a notification or a dialog to the user
if (bNotifyUser)
{
FNotificationInfo Info(ErrorMsg);
FSlateNotificationManager::Get().AddNotification(Info);
}
else
{
FMessageDialog::Open(EAppMsgType::Ok, ErrorMsg);
}
}
return bInASafeMode;
}
UEdMode* FEditorModeTools::GetActiveScriptableMode(FEditorModeID InID) const
{
for (auto& Mode: ActiveScriptableModes)
{
if (Mode->GetID() == InID)
{
return Mode;
}
}
return nullptr;
}
/**
* Returns a coordinate system that should be applied on top of the worldspace system.
*/
FMatrix FEditorModeTools::GetCustomDrawingCoordinateSystem()
{
FMatrix Matrix = FMatrix::Identity;
switch (GetCoordSystem())
{
case COORD_Local: {
Matrix = GetLocalCoordinateSystem();
}
break;
case COORD_World:
break;
default:
break;
}
return Matrix;
}
FMatrix FEditorModeTools::GetCustomInputCoordinateSystem()
{
return GetCustomDrawingCoordinateSystem();
}
FMatrix FEditorModeTools::GetLocalCoordinateSystem()
{
FMatrix Matrix = FMatrix::Identity;
// Let the current mode have a shot at setting the local coordinate system.
// If it doesn't want to, create it by looking at the currently selected actors list.
bool CustomCoordinateSystemProvided = false;
for (UEdMode* Mode: ActiveScriptableModes)
{
FEdMode* LegacyMode = Mode->AsLegacyMode();
if (LegacyMode && LegacyMode->GetCustomDrawingCoordinateSystem(Matrix, nullptr))
{
CustomCoordinateSystemProvided = true;
break;
}
}
if (!CustomCoordinateSystemProvided)
{
if (USceneComponent* SceneComponent = GetSelectedComponents()->GetBottom<USceneComponent>())
{
Matrix = FQuatRotationMatrix(SceneComponent->GetComponentQuat());
}
else
{
const int32 Num = GetSelectedActors()->CountSelections<AActor>();
// Coordinate system needs to come from the last actor selected
if (Num > 0)
{
Matrix = FQuatRotationMatrix(GetSelectedActors()->GetBottom<AActor>()->GetActorQuat());
}
}
}
if (!Matrix.Equals(FMatrix::Identity))
{
Matrix.RemoveScaling();
}
return Matrix;
}
/** Gets the widget axis to be drawn */
EAxisList::Type FEditorModeTools::GetWidgetAxisToDraw(FWidget::EWidgetMode InWidgetMode) const
{
EAxisList::Type OutAxis = EAxisList::All;
for (int Index = ActiveScriptableModes.Num() - 1; Index >= 0; Index--)
{
FEdMode* Mode = ActiveScriptableModes[Index]->AsLegacyMode();
if (Mode && Mode->ShouldDrawWidget())
{
OutAxis = Mode->GetWidgetAxisToDraw(InWidgetMode);
break;
}
}
return OutAxis;
}
/** Mouse tracking interface. Passes tracking messages to all active modes */
bool FEditorModeTools::StartTracking(FEditorViewportClient* InViewportClient, FViewport* InViewport)
{
bIsTracking = true;
bool bTransactionHandled = false;
CachedLocation = PivotLocation; // Cache the pivot location
for (UEdMode* Mode: ActiveScriptableModes)
{
bTransactionHandled |= Mode->StartTracking(InViewportClient, InViewportClient->Viewport);
}
return bTransactionHandled;
}
/** Mouse tracking interface. Passes tracking messages to all active modes */
bool FEditorModeTools::EndTracking(FEditorViewportClient* InViewportClient, FViewport* InViewport)
{
bIsTracking = false;
bool bTransactionHandled = false;
for (UEdMode* Mode: ActiveScriptableModes)
{
bTransactionHandled |= Mode->EndTracking(InViewportClient, InViewportClient->Viewport);
}
CachedLocation = PivotLocation; // Clear the pivot location
return bTransactionHandled;
}
bool FEditorModeTools::AllowsViewportDragTool() const
{
bool bCanUseDragTool = false;
for (UEdMode* Mode: ActiveScriptableModes)
{
if (FEdMode* LegacyMode = Mode->AsLegacyMode())
{
bCanUseDragTool |= LegacyMode->AllowsViewportDragTool();
}
}
return bCanUseDragTool;
}
/** Notifies all active modes that a map change has occured */
void FEditorModeTools::MapChangeNotify()
{
for (UEdMode* Mode: ActiveScriptableModes)
{
Mode->MapChangeNotify();
}
}
/** Notifies all active modes to empty their selections */
void FEditorModeTools::SelectNone()
{
for (UEdMode* Mode: ActiveScriptableModes)
{
Mode->SelectNone();
}
}
/** Notifies all active modes of box selection attempts */
bool FEditorModeTools::BoxSelect(FBox& InBox, bool InSelect)
{
bool bHandled = false;
for (UEdMode* Mode: ActiveScriptableModes)
{
if (FEdMode* LegacyMode = Mode->AsLegacyMode())
{
bHandled |= LegacyMode->BoxSelect(InBox, InSelect);
}
}
return bHandled;
}
/** Notifies all active modes of frustum selection attempts */
bool FEditorModeTools::FrustumSelect(const FConvexVolume& InFrustum, FEditorViewportClient* InViewportClient, bool InSelect)
{
bool bHandled = false;
for (UEdMode* Mode: ActiveScriptableModes)
{
if (FEdMode* LegacyMode = Mode->AsLegacyMode())
{
bHandled |= LegacyMode->FrustumSelect(InFrustum, InViewportClient, InSelect);
}
}
return bHandled;
}
/** true if any active mode uses a transform widget */
bool FEditorModeTools::UsesTransformWidget() const
{
bool bUsesTransformWidget = false;
for (UEdMode* Mode: ActiveScriptableModes)
{
if (FEdMode* LegacyMode = Mode->AsLegacyMode())
{
bUsesTransformWidget |= LegacyMode->UsesTransformWidget();
}
}
return bUsesTransformWidget;
}
/** true if any active mode uses the passed in transform widget */
bool FEditorModeTools::UsesTransformWidget(FWidget::EWidgetMode CheckMode) const
{
bool bUsesTransformWidget = false;
for (UEdMode* Mode: ActiveScriptableModes)
{
if (FEdMode* LegacyMode = Mode->AsLegacyMode())
{
bUsesTransformWidget |= LegacyMode->UsesTransformWidget(CheckMode);
}
}
return bUsesTransformWidget;
}
/** Sets the current widget axis */
void FEditorModeTools::SetCurrentWidgetAxis(EAxisList::Type NewAxis)
{
for (UEdMode* Mode: ActiveScriptableModes)
{
if (FEdMode* LegacyMode = Mode->AsLegacyMode())
{
LegacyMode->SetCurrentWidgetAxis(NewAxis);
}
}
}
/** Notifies all active modes of mouse click messages. */
bool FEditorModeTools::HandleClick(FEditorViewportClient* InViewportClient, HHitProxy* HitProxy, const FViewportClick& Click)
{
bool bHandled = false;
for (UEdMode* Mode: ActiveScriptableModes)
{
bHandled |= Mode->HandleClick(InViewportClient, HitProxy, Click);
}
return bHandled;
}
bool FEditorModeTools::ComputeBoundingBoxForViewportFocus(AActor* Actor, UPrimitiveComponent* PrimitiveComponent, FBox& InOutBox)
{
bool bHandled = false;
for (const UEdMode* Mode: ActiveScriptableModes)
{
bHandled |= Mode->ComputeBoundingBoxForViewportFocus(Actor, PrimitiveComponent, InOutBox);
}
return bHandled;
}
/** true if the passed in brush actor should be drawn in wireframe */
bool FEditorModeTools::ShouldDrawBrushWireframe(AActor* InActor) const
{
bool bShouldDraw = false;
for (const UEdMode* Mode: ActiveScriptableModes)
{
bShouldDraw |= Mode->ShouldDrawBrushWireframe(InActor);
}
if ((ActiveScriptableModes.Num() == 0))
{
// We can get into a state where there are no active modes at editor startup if the builder brush is created before the default mode is activated.
// Ensure we can see the builder brush when no modes are active.
bShouldDraw = true;
}
return bShouldDraw;
}
/** true if brush vertices should be drawn */
bool FEditorModeTools::ShouldDrawBrushVertices() const
{
if (UBrushEditingSubsystem* BrushSubsystem = GEditor->GetEditorSubsystem<UBrushEditingSubsystem>())
{
// Currently only geometry mode being active prevents vertices from being drawn.
return !BrushSubsystem->IsGeometryEditorModeActive();
}
return true;
}
/** Ticks all active modes */
void FEditorModeTools::Tick(FEditorViewportClient* ViewportClient, float DeltaTime)
{
// Remove anything pending destruction
for (int32 Index = ActiveScriptableModes.Num() - 1; Index >= 0; --Index)
{
if (ActiveScriptableModes[Index]->IsPendingDeletion())
{
DeactivateScriptableModeAtIndex(Index);
}
}
if (ActiveScriptableModes.Num() == 0)
{
// Ensure the default mode is active if there are no active modes.
ActivateDefaultMode();
}
for (UEdMode* Mode: ActiveScriptableModes)
{
Mode->Tick(ViewportClient, DeltaTime);
}
}
/** Notifies all active modes of any change in mouse movement */
bool FEditorModeTools::InputDelta(FEditorViewportClient* InViewportClient, FViewport* InViewport, FVector& InDrag, FRotator& InRot, FVector& InScale)
{
bool bHandled = false;
for (UEdMode* Mode: ActiveScriptableModes)
{
bHandled |= Mode->InputDelta(InViewportClient, InViewport, InDrag, InRot, InScale);
}
return bHandled;
}
/** Notifies all active modes of captured mouse movement */
bool FEditorModeTools::CapturedMouseMove(FEditorViewportClient* InViewportClient, FViewport* InViewport, int32 InMouseX, int32 InMouseY)
{
bool bHandled = false;
for (UEdMode* Mode: ActiveScriptableModes)
{
bHandled |= Mode->CapturedMouseMove(InViewportClient, InViewport, InMouseX, InMouseY);
}
return bHandled;
}
/** Notifies all active modes of all captured mouse movement */
bool FEditorModeTools::ProcessCapturedMouseMoves(FEditorViewportClient* InViewportClient, FViewport* InViewport, const TArrayView<FIntPoint>& CapturedMouseMoves)
{
bool bHandled = false;
for (UEdMode* Mode: ActiveScriptableModes)
{
bHandled |= Mode->ProcessCapturedMouseMoves(InViewportClient, InViewport, CapturedMouseMoves);
}
return bHandled;
}
/** Notifies all active modes of keyboard input */
bool FEditorModeTools::InputKey(FEditorViewportClient* InViewportClient, FViewport* Viewport, FKey Key, EInputEvent Event)
{
bool bHandled = false;
// Copy the modes and iterate of that since a key may remove the edit mode and change CopyActiveScriptableModes
TArray<UEdMode*> CopyActiveScriptableModes(ActiveScriptableModes);
for (UEdMode* Mode: CopyActiveScriptableModes)
{
bHandled |= Mode->InputKey(InViewportClient, Viewport, Key, Event);
}
return bHandled;
}
/** Notifies all active modes of axis movement */
bool FEditorModeTools::InputAxis(FEditorViewportClient* InViewportClient, FViewport* Viewport, int32 ControllerId, FKey Key, float Delta, float DeltaTime)
{
bool bHandled = false;
for (UEdMode* Mode: ActiveScriptableModes)
{
bHandled |= Mode->InputAxis(InViewportClient, Viewport, ControllerId, Key, Delta, DeltaTime);
}
return bHandled;
}
bool FEditorModeTools::GetPivotForOrbit(FVector& Pivot) const
{
// Just return the first pivot point specified by a mode
for (UEdMode* Mode: ActiveScriptableModes)
{
if (Mode->GetPivotForOrbit(Pivot))
{
return true;
}
}
return false;
}
bool FEditorModeTools::MouseEnter(FEditorViewportClient* InViewportClient, FViewport* Viewport, int32 X, int32 Y)
{
HoveredViewportClient = InViewportClient;
bool bHandled = false;
for (UEdMode* Mode: ActiveScriptableModes)
{
bHandled |= Mode->MouseEnter(InViewportClient, Viewport, X, Y);
}
return bHandled;
}
bool FEditorModeTools::MouseLeave(FEditorViewportClient* InViewportClient, FViewport* Viewport)
{
bool bHandled = false;
for (UEdMode* Mode: ActiveScriptableModes)
{
bHandled |= Mode->MouseLeave(InViewportClient, Viewport);
}
return bHandled;
}
/** Notifies all active modes that the mouse has moved */
bool FEditorModeTools::MouseMove(FEditorViewportClient* InViewportClient, FViewport* Viewport, int32 X, int32 Y)
{
bool bHandled = false;
for (UEdMode* Mode: ActiveScriptableModes)
{
bHandled |= Mode->MouseMove(InViewportClient, Viewport, X, Y);
}
return bHandled;
}
bool FEditorModeTools::ReceivedFocus(FEditorViewportClient* InViewportClient, FViewport* Viewport)
{
FocusedViewportClient = InViewportClient;
bool bHandled = false;
for (UEdMode* Mode: ActiveScriptableModes)
{
bHandled |= Mode->ReceivedFocus(InViewportClient, Viewport);
}
return bHandled;
}
bool FEditorModeTools::LostFocus(FEditorViewportClient* InViewportClient, FViewport* Viewport)
{
bool bHandled = false;
for (UEdMode* Mode: ActiveScriptableModes)
{
bHandled |= Mode->LostFocus(InViewportClient, Viewport);
}
return bHandled;
}
/** Draws all active mode components */
void FEditorModeTools::DrawActiveModes(const FSceneView* InView, FPrimitiveDrawInterface* PDI)
{
for (UEdMode* Mode: ActiveScriptableModes)
{
Mode->Draw(InView, PDI);
}
}
/** Renders all active modes */
void FEditorModeTools::Render(const FSceneView* InView, FViewport* Viewport, FPrimitiveDrawInterface* PDI)
{
for (UEdMode* Mode: ActiveScriptableModes)
{
Mode->Render(InView, Viewport, PDI);
}
}
/** Draws the HUD for all active modes */
void FEditorModeTools::DrawHUD(FEditorViewportClient* InViewportClient, FViewport* Viewport, const FSceneView* View, FCanvas* Canvas)
{
for (UEdMode* Mode: ActiveScriptableModes)
{
Mode->DrawHUD(InViewportClient, Viewport, View, Canvas);
}
}
/** Calls PostUndo on all active modes */
void FEditorModeTools::PostUndo(bool bSuccess)
{
if (bSuccess)
{
for (UEdMode* Mode: ActiveScriptableModes)
{
Mode->PostUndo();
}
}
}
void FEditorModeTools::PostRedo(bool bSuccess)
{
PostUndo(bSuccess);
}
/** true if we should allow widget move */
bool FEditorModeTools::AllowWidgetMove() const
{
bool bAllow = false;
for (UEdMode* Mode: ActiveScriptableModes)
{
if (FEdMode* LegacyMode = Mode->AsLegacyMode())
{
bAllow |= LegacyMode->AllowWidgetMove();
}
}
return bAllow;
}
bool FEditorModeTools::DisallowMouseDeltaTracking() const
{
bool bDisallow = false;
for (const UEdMode* Mode: ActiveScriptableModes)
{
bDisallow |= Mode->DisallowMouseDeltaTracking();
}
return bDisallow;
}
bool FEditorModeTools::GetCursor(EMouseCursor::Type& OutCursor) const
{
bool bHandled = false;
for (const UEdMode* Mode: ActiveScriptableModes)
{
bHandled |= Mode->GetCursor(OutCursor);
}
return bHandled;
}
bool FEditorModeTools::GetOverrideCursorVisibility(bool& bWantsOverride, bool& bHardwareCursorVisible, bool bSoftwareCursorVisible) const
{
bool bHandled = false;
for (const UEdMode* Mode: ActiveScriptableModes)
{
bHandled |= Mode->GetOverrideCursorVisibility(bWantsOverride, bHardwareCursorVisible, bSoftwareCursorVisible);
}
return bHandled;
}
bool FEditorModeTools::PreConvertMouseMovement(FEditorViewportClient* InViewportClient)
{
bool bHandled = false;
for (UEdMode* Mode: ActiveScriptableModes)
{
bHandled |= Mode->PreConvertMouseMovement(InViewportClient);
}
return bHandled;
}
bool FEditorModeTools::PostConvertMouseMovement(FEditorViewportClient* InViewportClient)
{
bool bHandled = false;
for (UEdMode* Mode: ActiveScriptableModes)
{
bHandled |= Mode->PostConvertMouseMovement(InViewportClient);
}
return bHandled;
}
bool FEditorModeTools::GetShowWidget() const
{
bool bDrawModeSupportsWidgetDrawing = false;
// Check to see of any active modes support widget drawing
for (UEdMode* Mode: ActiveScriptableModes)
{
if (FEdMode* LegacyMode = Mode->AsLegacyMode())
{
bDrawModeSupportsWidgetDrawing |= LegacyMode->ShouldDrawWidget();
}
}
return bDrawModeSupportsWidgetDrawing && bShowWidget;
}
/**
* Used to cycle widget modes
*/
void FEditorModeTools::CycleWidgetMode(void)
{
// make sure we're not currently tracking mouse movement. If we are, changing modes could cause a crash due to referencing an axis/plane that is incompatible with the widget
for (FLevelEditorViewportClient* ViewportClient: GEditor->GetLevelViewportClients())
{
if (ViewportClient->IsTracking())
{
return;
}
}
// only cycle when the mode is requesting the drawing of a widget
if (GetShowWidget())
{
const int32 CurrentWk = GetWidgetMode();
int32 Wk = CurrentWk;
do
{
Wk++;
if ((Wk == FWidget::WM_TranslateRotateZ) && (!GetDefault<ULevelEditorViewportSettings>()->bAllowTranslateRotateZWidget))
{
Wk++;
}
// Roll back to the start if we go past FWidget::WM_Scale
if (Wk >= FWidget::WM_Max)
{
Wk -= FWidget::WM_Max;
}
} while (!UsesTransformWidget((FWidget::EWidgetMode)Wk) && Wk != CurrentWk);
SetWidgetMode((FWidget::EWidgetMode)Wk);
FEditorSupportDelegates::RedrawAllViewports.Broadcast();
}
}
/**Save Widget Settings to Ini file*/
void FEditorModeTools::SaveWidgetSettings(void)
{
GetMutableDefault<UEditorPerProjectUserSettings>()->SaveConfig();
}
/**Load Widget Settings from Ini file*/
void FEditorModeTools::LoadWidgetSettings(void)
{
}
/**
* Returns a good location to draw the widget at.
*/
FVector FEditorModeTools::GetWidgetLocation() const
{
for (int Index = ActiveScriptableModes.Num() - 1; Index >= 0; Index--)
{
if (FEdMode* LegacyMode = ActiveScriptableModes[Index]->AsLegacyMode())
{
if (LegacyMode->UsesTransformWidget())
{
return LegacyMode->GetWidgetLocation();
}
}
}
return FVector(ForceInitToZero);
}
/**
* Changes the current widget mode.
*/
void FEditorModeTools::SetWidgetMode(FWidget::EWidgetMode InWidgetMode)
{
WidgetMode = InWidgetMode;
}
/**
* Allows you to temporarily override the widget mode. Call this function again
* with FWidget::WM_None to turn off the override.
*/
void FEditorModeTools::SetWidgetModeOverride(FWidget::EWidgetMode InWidgetMode)
{
OverrideWidgetMode = InWidgetMode;
}
/**
* Retrieves the current widget mode, taking overrides into account.
*/
FWidget::EWidgetMode FEditorModeTools::GetWidgetMode() const
{
if (OverrideWidgetMode != FWidget::WM_None)
{
return OverrideWidgetMode;
}
return WidgetMode;
}
/**
* Set Scale On The Widget
*/
void FEditorModeTools::SetWidgetScale(float InScale)
{
WidgetScale = InScale;
}
/**
* Get Scale On The Widget
*/
float FEditorModeTools::GetWidgetScale() const
{
return WidgetScale;
}
bool FEditorModeTools::GetShowFriendlyVariableNames()
{
return GetDefault<UEditorStyleSettings>()->bShowFriendlyNames;
}
const uint32 FEditorModeTools::GetMaxNumberOfBookmarks(FEditorViewportClient* InViewportClient)
{
return IBookmarkTypeTools::Get().GetMaxNumberOfBookmarks(InViewportClient);
}
void FEditorModeTools::CompactBookmarks(FEditorViewportClient* InViewportClient)
{
IBookmarkTypeTools::Get().CompactBookmarks(InViewportClient);
}
/**
* Sets a bookmark in the levelinfo file, allocating it if necessary.
*/
void FEditorModeTools::SetBookmark(uint32 InIndex, FEditorViewportClient* InViewportClient)
{
IBookmarkTypeTools::Get().CreateOrSetBookmark(InIndex, InViewportClient);
}
/**
* Checks to see if a bookmark exists at a given index
*/
bool FEditorModeTools::CheckBookmark(uint32 InIndex, FEditorViewportClient* InViewportClient)
{
return IBookmarkTypeTools::Get().CheckBookmark(InIndex, InViewportClient);
}
/**
* Retrieves a bookmark from the list.
*/
void FEditorModeTools::JumpToBookmark(uint32 InIndex, TSharedPtr<FBookmarkBaseJumpToSettings> InSettings, FEditorViewportClient* InViewportClient)
{
IBookmarkTypeTools::Get().JumpToBookmark(InIndex, InSettings, InViewportClient);
}
/**
* Clears a bookmark
*/
void FEditorModeTools::ClearBookmark(uint32 InIndex, FEditorViewportClient* InViewportClient)
{
IBookmarkTypeTools::Get().ClearBookmark(InIndex, InViewportClient);
}
/**
* Clears all book marks
*/
void FEditorModeTools::ClearAllBookmarks(FEditorViewportClient* InViewportClient)
{
IBookmarkTypeTools::Get().ClearAllBookmarks(InViewportClient);
}
void FEditorModeTools::AddReferencedObjects(FReferenceCollector& Collector)
{
Collector.AddReferencedObjects(ActiveScriptableModes);
Collector.AddReferencedObjects(RecycledScriptableModes);
}
FEdMode* FEditorModeTools::GetActiveMode(FEditorModeID InID)
{
if (UEdMode* Mode = GetActiveScriptableMode(InID))
{
return Mode->AsLegacyMode();
}
return nullptr;
}
const FEdMode* FEditorModeTools::GetActiveMode(FEditorModeID InID) const
{
if (UEdMode* Mode = GetActiveScriptableMode(InID))
{
return Mode->AsLegacyMode();
}
return nullptr;
}
const FModeTool* FEditorModeTools::GetActiveTool(FEditorModeID InID) const
{
const FEdMode* ActiveMode = GetActiveMode(InID);
const FModeTool* Tool = nullptr;
if (ActiveMode)
{
Tool = ActiveMode->GetCurrentTool();
}
return Tool;
}
bool FEditorModeTools::IsModeActive(FEditorModeID InID) const
{
if (GetActiveMode(InID) != nullptr)
{
return true;
}
else if (GetActiveScriptableMode(InID) != nullptr)
{
return true;
}
return false;
}
bool FEditorModeTools::IsDefaultModeActive() const
{
bool bAllDefaultModesActive = true;
for (const FEditorModeID& ModeID: DefaultModeIDs)
{
if (!IsModeActive(ModeID))
{
bAllDefaultModesActive = false;
break;
}
}
return bAllDefaultModesActive;
}
bool FEditorModeTools::CanCycleWidgetMode() const
{
for (UEdMode* Mode: ActiveScriptableModes)
{
if (FEdMode* LegacyMode = Mode->AsLegacyMode())
{
if (LegacyMode->CanCycleWidgetMode())
{
return true;
}
}
}
return false;
}
bool FEditorModeTools::CanAutoSave() const
{
for (const UEdMode* Mode: ActiveScriptableModes)
{
if (Mode->CanAutoSave() == false)
{
return false;
}
}
return true;
}