// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "CoreMinimal.h" #include "Input/Reply.h" #include "Widgets/SWidget.h" #include "Widgets/DeclarativeSyntaxSupport.h" #include "Engine/World.h" #include "Widgets/SWindow.h" #include "SLevelViewport.h" #include "Framework/Commands/UICommandList.h" #include "Framework/Docking/TabManager.h" #include "Toolkits/IToolkit.h" #include "AssetThumbnail.h" #include "ILevelEditor.h" #include "LevelViewportTabContent.h" #include "SLevelEditorToolBox.h" #include "ActorDetailsSCSEditorUICustomization.h" class IAssetEditorInstance; class IDetailsView; class SActorDetails; class SBorder; class SDockTab; class SLevelEditorModeContent; class SLevelEditorToolBox; class UTypedElementSelectionSet; namespace UE::WorldHierarchy { class IWorldHierarchy; } /** * Unreal editor level editor Slate widget */ class SLevelEditor : public ILevelEditor { public: SLATE_BEGIN_ARGS( SLevelEditor ){} SLATE_END_ARGS() /** * Constructor */ SLevelEditor(); ~SLevelEditor(); /** * Constructs this widget * * @param InArgs Declaration from which to construct the widget */ void Construct( const FArguments& InArgs ); /** * Initialize the newly constructed level editor UI, needed because restoring the layout could trigger showing tabs * that immediately try to get a reference to the current level editor. */ void Initialize( const TSharedRef& OwnerTab, const TSharedRef& OwnerWindow ); /** * Gets the currently active viewport in the level editor * @todo Slate: Needs a better implementation * * @return The active viewport. If multiple are active it returns the first one */ TSharedPtr GetActiveViewport() const; /** ILevelEditor interface */ virtual const UTypedElementSelectionSet* GetElementSelectionSet() const override; virtual UTypedElementSelectionSet* GetMutableElementSelectionSet() override; virtual void SummonLevelViewportContextMenu(const FTypedElementHandle& HitProxyElement = FTypedElementHandle()) override; virtual FText GetLevelViewportContextMenuTitle() const override; virtual void SummonLevelViewportViewOptionMenu(const ELevelViewportType ViewOption) override; virtual const TArray< TSharedPtr< class IToolkit > >& GetHostedToolkits() const override; virtual TArray< TSharedPtr< SLevelViewport > > GetViewports() const override; virtual TSharedPtr GetActiveViewportInterface() override; virtual void AppendCommands( const TSharedRef& InCommandsToAppend ) override; virtual void AddStandaloneLevelViewport( const TSharedRef& LevelViewport ) override; /** * Given a tab ID, summons a new tab in the position saved in the current layout, or in a default position. * @return the invoked tab */ TSharedPtr TryInvokeTab( FName TabID ); /** * Sync the details panel to the current selection * Will spawn a new details window if required (and possible) due to other details windows being locked */ void SyncDetailsToSelection(); /** * @return true if the level editor has a viewport currently being used for pie */ bool HasActivePlayInEditorViewport() const; /** @return Returns the title to display in the level editor's tab label */ FText GetTabTitle() const; /** @return Returns the suffix to display in the level editor's after tab label */ FText GetTabSuffix() const; /** * Processes level editor keybindings using events made in a viewport * * @param MyGeometry Information about the size and position of the viewport widget * @param InKeyEvent The event which just occurred */ virtual FReply OnKeyDownInViewport( const FGeometry& MyGeometry, const FKeyEvent& InKeyEvent ) override; /** Returns the full action list for this level editor instance */ virtual const TSharedPtr< FUICommandList >& GetLevelEditorActions() const override { return LevelEditorCommands; } /** IToolKitHost interface */ virtual TSharedRef< class SWidget > GetParentWidget() override; virtual void BringToFront() override; virtual TSharedPtr GetTabManager() const override; virtual void OnToolkitHostingStarted( const TSharedRef< class IToolkit >& Toolkit ) override; virtual void OnToolkitHostingFinished( const TSharedRef< class IToolkit >& Toolkit ) override; virtual UWorld* GetWorld() const override; virtual TSharedRef CreateActorDetails( const FName TabIdentifier ) override; virtual void SetActorDetailsRootCustomization(TSharedPtr InActorDetailsObjectFilter, TSharedPtr InActorDetailsRootCustomization) override; virtual void AddActorDetailsSCSEditorUICustomization(TSharedPtr ActorDetailsSCSEditorUICustomization) override; virtual void RemoveActorDetailsSCSEditorUICustomization(TSharedPtr ActorDetailsSCSEditorUICustomization) override; virtual FEditorModeTools& GetEditorModeManager() const override; virtual UTypedElementCommonActions* GetCommonActions() const override; virtual FName GetStatusBarName() const override; virtual FOnActiveViewportChanged& OnActiveViewportChanged() { return OnActiveViewportChangedDelegate; } virtual void AddViewportOverlayWidget(TSharedRef, int32 ZOrder = INDEX_NONE, TSharedPtr InViewport = nullptr) override; virtual void RemoveViewportOverlayWidget(TSharedRef, TSharedPtr InViewport = nullptr) override; virtual FVector2f GetActiveViewportWidgetSize() const override; /* Tick to check the ActiveViewport */ virtual void Tick(const FGeometry& AllottedGeometry, const double InCurrentTime, const float InDeltaTime) override; /** SWidget overrides */ virtual bool SupportsKeyboardFocus() const override { return true; } /** Attaches a sequencer asset editor used to animate objects in the level to this level editor */ TSharedPtr AttachSequencer( TSharedPtr SequencerWidget, TSharedPtr NewSequencerAssetEditor ); /** Get an array containing weak pointers to all 4 Scene Outliners which could be potentially active */ virtual TArray> GetAllSceneOutliners() const override; /** Set the outliner with the given name as the most recently interacted with */ virtual void SetMostRecentlyUsedSceneOutliner(FName OutlinerIdentifier) override; /** Return the most recently interacted with Outliner */ virtual TSharedPtr GetMostRecentlyUsedSceneOutliner() override; virtual TWeakPtr GetWorldHierarchy() override { return WorldHierarchy; } TSharedRef GetTitleBarMessageWidget() const { return TtileBarMessageBox.ToSharedRef(); } private: TSharedRef SpawnLevelEditorTab(const FSpawnTabArgs& Args, FName TabIdentifier, FString InitializationPayload); bool CanSpawnLevelEditorTab(const FSpawnTabArgs& Args, FName TabIdentifier); //TSharedRef SpawnLevelEditorModeTab(const FSpawnTabArgs& Args, FEdMode* EditorMode); TSharedRef SummonDetailsPanel( FName Identifier ); /** * Binds UI commands to actions for the level editor */ void BindCommands(); /** Registers menus associated with level editor */ void RegisterMenus(); /** * Fills the level editor with content, using the layout string, or the default if * no layout string is passed in */ TSharedRef RestoreContentArea( const TSharedRef& OwnerTab, const TSharedRef& OwnerWindow ); /** Called when a property is changed */ void HandleExperimentalSettingChanged(FName PropertyName); /** Rebuilds the command list for spawning editor modes, this is done when new modes are registered. */ void RefreshEditorModeCommands(); /** Editor mode has been added or removed, clears cached command list so it will be rebuilt */ void EditorModeCommandsChanged(); /** Gets the tabId mapping to an editor mode */ static FName GetEditorModeTabId( FEditorModeID ModeID ); /** Toggles the editor mode on and off, this is what the auto generated editor mode commands are mapped to. */ void ToggleEditorMode( FEditorModeID ModeID ); /** Checks if the editor mode is active for the auto-generated editor mode command. */ bool IsModeActive(FEditorModeID ModeID); /** Checks if the editor mode is visible for the auto-generated editor mode command. */ bool ShouldShowModeInToolbar(FEditorModeID ModeID); /** * Processes keybindings on the level editor * * @param MyGeometry Information about the size and position of the level editor widget * @param InKeyEvent The event which just occurred */ virtual FReply OnKeyDown( const FGeometry& MyGeometry, const FKeyEvent& InKeyEvent ) override; /** Callback for when the level editor layout has changed */ void OnLayoutHasChanged(); /** Constructs the title bar message widget */ void ConstructTitleBarMessages(); /** Builds a viewport tab. */ TSharedRef BuildViewportTab( const FText& Label, const FString LayoutId, const FString& InitializationPayload ); /** Called when a viewport tab is closed */ void OnViewportTabClosed(TSharedRef ClosedTab); /** Called when the toolbox tab is closed */ void OnToolboxTabClosed(TSharedRef ClosedTab); /** Save the information about the given viewport in the transient viewport information */ void SaveViewportTabInfo(TSharedRef ViewportTabContent); /** Restore the information about the given viewport from the transient viewport information */ void RestoreViewportTabInfo(TSharedRef ViewportTabContent) const; /** Reset the transient viewport information */ void ResetViewportTabInfo(); /** Handles Editor map changes */ void HandleEditorMapChange( uint32 MapChangeFlags ); /** Handles deletion of assets */ void HandleAssetsDeleted(const TArray& DeletedClasses); /** Handles events where an instance of an Instanced Static Mesh is about to be removed. */ void OnIsmInstanceRemoving(const FSMInstanceElementId& SMInstanceElementId, int32 InstanceIndex); /** Called when element selection changes */ void OnElementSelectionChanged(const UTypedElementSelectionSet* SelectionSet, bool bForceRefresh = false); /** Called when actor selection changes */ void OnActorSelectionChanged(const TArray& NewSelection, bool bForceRefresh); /** Called to set property editors to show the given actors, even if those actors aren't in the current selection set */ void OnOverridePropertyEditorSelection(const TArray& NewSelection, bool bForceRefresh = false); /** Called when an actor is destroyed */ void OnLevelActorDeleted(AActor* InActor); /** Called when an actor changes outer */ void OnLevelActorOuterChanged(AActor* InActor = nullptr, UObject* InOldOuter = nullptr); /** Registers toolbar options for the level editor status bar */ void RegisterStatusBarTools(); /** @return All valid actor details panels */ TArray> GetAllActorDetails() const; /** Create a Scene Outliner for the Level Editor */ TSharedRef CreateSceneOutliner(FName TabIdentifier); /** Function to extend the context menu for the outliner tab */ void OnExtendSceneOutlinerTabContextMenu(FMenuBuilder& InMenuBuilder); /** Helper function to get the display name for an outliner */ FText GetSceneOutlinerLabel(FName SceneOutlinerTabIdentifier); /** Sets the first available outliner as the most recent outliner */ void ResetMostRecentOutliner(); private: // Tracking the active viewports in this level editor. TArray< TWeakPtr > ViewportTabs; // A list of any standalone editor viewports that aren't in tabs TArray< TWeakPtr > StandaloneViewports; // The last known active viewport TWeakPtr CachedActiveViewport; // Border that hosts the document content for the level editor. TSharedPtr< SBorder > DocumentsAreaBorder; // The list of commands with bound delegates for the level editor. TSharedPtr LevelEditorCommands; // Weak reference to all toolbox panels this level editor has spawned. May contain invalid entries for tabs that were closed. TArray< TWeakPtr< class SLevelEditorToolBox > > ToolBoxTabs; // List of all of the toolkits we're currently hosting. TArray< TSharedPtr< class IToolkit > > HostedToolkits; // The UWorld that this level editor is viewing and allowing the user to interact with through. UWorld* World; // The list of selected elements (also set on the global USelection for actors and components). UTypedElementSelectionSet* SelectedElements = nullptr; // The common actions implementation for the level editor UTypedElementCommonActions* CommonActions = nullptr; // The box that holds the title bar messages. TSharedPtr TtileBarMessageBox; // Holds the world settings details view. TSharedPtr WorldSettingsView; /** Transient editor viewport states - one for each view type. Key is "LayoutId[ELevelViewportType]", eg) "Viewport 1[0]" */ TMap TransientEditorViews; /** List of all actor details panels to update when selection changes */ TArray< TWeakPtr > AllActorDetailPanels; /** Attached sequencer asset editor */ TWeakPtr SequencerAssetEditor; /** Weak pointer to the level editor's Sequencer widget */ TWeakPtr SequencerWidgetPtr; /** Weak pointer to the level editor's most recently created scene outliner */ TWeakPtr SceneOutlinerPtr; /** The content displayed by the LevelEditorTabIds::WorldBrowserHierarchy tab. */ TWeakPtr WorldHierarchy; /** Map containing Weak pointers to all the Outliners in the level editor */ TMap> SceneOutliners; /** Map containing Weak pointers to all the Scene Outliner Tabs in the level editor */ TMap> SceneOutlinerTabs; /** Map containing the display names of all the outliners */ TMap SceneOutlinerDisplayNames; /** Handle to the registered OnPreviewFeatureLevelChanged delegate. */ FDelegateHandle PreviewFeatureLevelChangedHandle; /** Handle to the registered OnPreviewPlatformChanged delegate. */ FDelegateHandle PreviewPlatformChangedHandle; /** Handle to the registered OnLevelActorDeleted delegate */ FDelegateHandle LevelActorDeletedHandle; /** Handle to the registered OnLevelActorOuterChanged delegate */ FDelegateHandle LevelActorOuterChangedHandle; /** Actor details object filters */ TSharedPtr ActorDetailsObjectFilter; /** Actor details root customization */ TSharedPtr ActorDetailsRootCustomization; /** Actor details SCS editor customization */ TSharedPtr ActorDetailsSCSEditorUICustomization; /** A delegate which is called any time the LevelEditor's active viewport changes. */ FOnActiveViewportChanged OnActiveViewportChangedDelegate; /** If this flag is raised we will force refresh on next selection update. */ bool bNeedsRefresh : 1; TMap> ModeUILayers; /** Pointer to the widget that houses the level editor's mode toolbar */ TSharedPtr SecondaryModeToolbarWidget; /** Viewport context menu title, cached each time the element selection set changes */ FText CachedViewportContextMenuTitle; };