2014-12-07 19:09:38 -05:00
// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
2014-03-14 14:13:41 -04:00
# include "LevelEditor.h"
# include "SToolkitDisplay.h"
# include "SLevelEditorToolBox.h"
# include "Toolkits/IToolkit.h"
# include "Toolkits/ToolkitManager.h"
# include "Toolkits/AssetEditorToolkit.h"
# include "Toolkits/SAssetEditorCommon.h"
2014-10-14 22:50:06 -04:00
# include "SHyperlink.h"
2014-03-14 14:13:41 -04:00
# define LOCTEXT_NAMESPACE "ToolkitDisplay"
void SLevelEditorActiveToolkit : : Construct ( const FArguments & , const TSharedPtr < IToolkit > & InitToolkit , const FEdMode * InitEditorMode )
{
Toolkit = InitToolkit ;
EditorMode = InitEditorMode ;
ActiveToolkitType = Toolkit . IsValid ( ) ? ELevelEditorActiveToolkit : : Toolkit : ELevelEditorActiveToolkit : : LegacyEditorMode ;
check ( ( ActiveToolkitType = = ELevelEditorActiveToolkit : : Toolkit & & Toolkit . IsValid ( ) ) | |
( ActiveToolkitType = = ELevelEditorActiveToolkit : : LegacyEditorMode & & EditorMode ! = NULL ) ) ;
const bool bIsAssetEditorToolkit = ActiveToolkitType = = ELevelEditorActiveToolkit : : Toolkit & & InitToolkit - > IsAssetEditor ( ) ;
// @todo toolkit major: Improve look of this:
// - draw icon for asset editor (e.g. blueprint icon)
// - Probably should appear in standalone version too!
// - make text more pronounced! maybe use two lines (put editor name on second line, smaller text?)
// - combo drop-down looks horrible...
//
// - highlight all related tabs on mouse over
// - maybe change to task bar styling?
// - icon to "tear out and edit standalone"? Or drag tear?
// - what about asset type or path?
// - animation transitions when mode is opened and killed?
// - animation when focusing tabs?
//
// - new toolkit doc area tabs should animate in (like they do when closing!) (see CreateNewTabStackBySplitting)
// - need visual cue when there are no toolkits around (currently just empty expando)
// - color distinction between modes and asset editors?
TSharedPtr < SHorizontalBox > ContentBox ;
ChildSlot
[
SNew ( SBorder )
. Padding ( 3.0f )
[
SNew ( SOverlay )
+ SOverlay : : Slot ( )
[
SNew ( SImage )
// Don't allow color overlay to absorb mouse clicks
. Visibility ( EVisibility : : HitTestInvisible )
. Image ( FEditorStyle : : GetBrush ( " ToolkitDisplay.ColorOverlay " ) )
. ColorAndOpacity ( this , & SLevelEditorActiveToolkit : : GetToolkitBackgroundOverlayColor )
]
+ SOverlay : : Slot ( )
[
SAssignNew ( ContentBox , SHorizontalBox )
+ SHorizontalBox : : Slot ( )
. FillWidth ( 1.0f )
[
SNew ( SHorizontalBox )
+ SHorizontalBox : : Slot ( )
. AutoWidth ( )
. Padding ( 4.0f , 7.0f , 3.0f , 3.0f )
[
// @todo toolkit major: Separate asset name from editor name (and draw unsaved change state next to asset part)
SNew ( SHyperlink )
. Text ( this , & SLevelEditorActiveToolkit : : GetToolkitTextLabel )
. OnNavigate ( this , & SLevelEditorActiveToolkit : : OnNavigateToToolkit )
]
// Asset modified state
+ SHorizontalBox : : Slot ( )
. AutoWidth ( )
. Padding ( 0.0f , 0.0f , 3.0f , 0.0f )
[
SNew ( SImage )
. Visibility ( this , & SLevelEditorActiveToolkit : : GetVisibilityForUnsavedChangeIcon )
. Image ( FEditorStyle : : GetBrush ( " ToolkitDisplay.UnsavedChangeIcon " ) )
2015-01-08 11:35:01 -05:00
. ToolTipText ( LOCTEXT ( " UnsavedChangeToolTip " , " This asset has unsaved changes " ) )
2014-03-14 14:13:41 -04:00
]
]
]
]
] ;
if ( bIsAssetEditorToolkit )
{
TSharedRef < FAssetEditorToolkit > AssetEditorToolkit = StaticCastSharedPtr < FAssetEditorToolkit > ( Toolkit ) . ToSharedRef ( ) ;
// We want the window to be closed after the user chooses an option from the drop-down
const bool bIsPopup = true ;
ContentBox - > AddSlot ( )
. AutoWidth ( )
2014-09-11 20:21:09 -04:00
. VAlign ( VAlign_Center )
2014-03-14 14:13:41 -04:00
. HAlign ( HAlign_Right )
[
SNew ( SComboButton )
2014-04-02 18:09:23 -04:00
. ComboButtonStyle ( FEditorStyle : : Get ( ) , " ToolkitDisplay.ComboButton " )
2014-03-14 14:13:41 -04:00
. ButtonContent ( )
[
SNew ( SImage )
. Image ( FEditorStyle : : GetBrush ( " ToolkitDisplay.MenuDropdown " ) )
]
. MenuContent ( )
[
SNew ( SAssetEditorCommon , AssetEditorToolkit , bIsPopup )
]
] ;
}
ContentBox - > AddSlot ( )
. AutoWidth ( )
. HAlign ( HAlign_Right ) // @todo toolkit major: Needs hover cue, visual polish, margins (probably should be consistent with tab close button)
. Padding ( 2.0f )
[
SNew ( SButton )
. OnClicked ( this , & SLevelEditorActiveToolkit : : OnToolkitCloseButtonClicked )
2015-01-08 11:35:01 -05:00
. ToolTipText ( LOCTEXT ( " CloseToolkitButton " , " Close " ) )
2014-03-14 14:13:41 -04:00
. ButtonStyle ( FEditorStyle : : Get ( ) , " NoBorder " )
. ContentPadding ( 0 )
. HAlign ( HAlign_Center )
. VAlign ( VAlign_Center )
. ForegroundColor ( FSlateColor : : UseForeground ( ) )
[
SNew ( SImage )
. Image ( FEditorStyle : : GetBrush ( " Symbols.X " ) )
. ColorAndOpacity ( FSlateColor : : UseForeground ( ) )
]
] ;
}
FText SLevelEditorActiveToolkit : : GetToolkitTextLabel ( ) const
{
if ( ActiveToolkitType = = ELevelEditorActiveToolkit : : LegacyEditorMode )
{
2014-06-18 10:16:16 -04:00
return EditorMode - > GetModeInfo ( ) . Name ;
2014-03-14 14:13:41 -04:00
}
else if ( ActiveToolkitType = = ELevelEditorActiveToolkit : : Toolkit )
{
return Toolkit - > GetToolkitName ( ) ;
}
return LOCTEXT ( " UnknownToolkitName " , " ??? " ) ;
}
FSlateColor SLevelEditorActiveToolkit : : GetToolkitBackgroundOverlayColor ( ) const
{
if ( ActiveToolkitType = = ELevelEditorActiveToolkit : : LegacyEditorMode )
{
// Don't bother coloring legacy editor modes
return FLinearColor ( 0 , 0 , 0 , 0 ) ;
}
else if ( ActiveToolkitType = = ELevelEditorActiveToolkit : : Toolkit )
{
return Toolkit - > GetWorldCentricTabColorScale ( ) ;
}
return FLinearColor ( 0 , 0 , 0 , 0 ) ;
}
void SLevelEditorActiveToolkit : : DeactivateMode ( )
{
if ( ActiveToolkitType = = ELevelEditorActiveToolkit : : LegacyEditorMode )
{
// Exit the mode. This will immediately call back to remove the active toolkit from our list
check ( EditorMode ! = NULL ) ;
2014-06-18 10:16:16 -04:00
GLevelEditorModeTools ( ) . DeactivateMode ( EditorMode - > GetID ( ) ) ;
2014-03-14 14:13:41 -04:00
}
else if ( ActiveToolkitType = = ELevelEditorActiveToolkit : : Toolkit )
{
// @todo toolkit minor: Should we force a "Save and Close" workflow? Basically, expect assets to be saved before they are closed out (and could be GC'd?)
// -> Doesn't really "work" unless we store off working copies (like material editor)
// NOTE: This will call back to the toolkit area and actually remove this active toolkit from our list!
if ( Toolkit . IsValid ( ) = = true )
{
FToolkitManager : : Get ( ) . CloseToolkit ( Toolkit . ToSharedRef ( ) ) ;
}
}
}
FReply SLevelEditorActiveToolkit : : OnToolkitCloseButtonClicked ( )
{
DeactivateMode ( ) ;
return FReply : : Handled ( ) ;
}
EVisibility SLevelEditorActiveToolkit : : GetVisibilityForUnsavedChangeIcon ( ) const
{
bool bShowUnsavedChangeIcon = false ;
const bool bIsAssetEditorToolkit = ActiveToolkitType = = ELevelEditorActiveToolkit : : Toolkit & & Toolkit - > IsAssetEditor ( ) ;
if ( bIsAssetEditorToolkit )
{
const TSharedRef < FAssetEditorToolkit > & AssetEditorToolkit = StaticCastSharedRef < FAssetEditorToolkit > ( Toolkit . ToSharedRef ( ) ) ;
const TArray < UObject * > & Assets = * AssetEditorToolkit - > GetObjectsCurrentlyBeingEdited ( ) ;
for ( int AssetIndex = 0 ; ! bShowUnsavedChangeIcon & & AssetIndex < Assets . Num ( ) ; + + AssetIndex )
{
const auto Asset = Assets [ AssetIndex ] ;
if ( Asset ! = NULL )
{
bShowUnsavedChangeIcon = Asset - > GetOutermost ( ) - > IsDirty ( ) ;
}
}
}
return bShowUnsavedChangeIcon ? EVisibility : : Visible : EVisibility : : Collapsed ;
}
void SLevelEditorActiveToolkit : : OnNavigateToToolkit ( )
{
if ( ActiveToolkitType = = ELevelEditorActiveToolkit : : Toolkit )
{
// User clicked the tool tip text, so we'll bring all of this toolkit's tabs to the front!
Toolkit - > BringToolkitToFront ( ) ;
}
}
void SToolkitDisplay : : Construct ( const FArguments & InArgs , const TSharedRef < class ILevelEditor > & OwningLevelEditor )
{
OnInlineContentChangedDelegate = InArgs . _OnInlineContentChanged ;
ChildSlot
[
SAssignNew ( VBox , SVerticalBox )
] ;
// Register with the mode system to find out when a mode is entered or exited
2014-06-18 10:16:16 -04:00
GLevelEditorModeTools ( ) . OnEditorModeChanged ( ) . AddSP ( SharedThis ( this ) , & SToolkitDisplay : : OnEditorModeChanged ) ;
2014-03-14 14:13:41 -04:00
// Find all of the current active modes and toolkits and add those right away. This widget could have been created "late"!
{
TArray < FEdMode * > ActiveModes ;
2014-06-18 10:16:16 -04:00
GLevelEditorModeTools ( ) . GetActiveModes ( ActiveModes ) ;
2014-03-14 14:13:41 -04:00
for ( auto EdModeIt = ActiveModes . CreateConstIterator ( ) ; EdModeIt ; + + EdModeIt )
{
// We don't care about the default editor mode. Just ignore it.
if ( ( * EdModeIt ) - > GetID ( ) ! = FBuiltinEditorModes : : EM_Default & & ! ( * EdModeIt ) - > UsesToolkits ( ) )
{
AddEditorMode ( * EdModeIt ) ;
}
}
const TArray < TSharedPtr < IToolkit > > & HostedToolkits = OwningLevelEditor - > GetHostedToolkits ( ) ;
for ( auto HostedToolkitIt = HostedToolkits . CreateConstIterator ( ) ; HostedToolkitIt ; + + HostedToolkitIt )
{
OnToolkitHostingStarted ( ( * HostedToolkitIt ) . ToSharedRef ( ) ) ;
}
}
}
SToolkitDisplay : : ~ SToolkitDisplay ( )
{
//the toolkit is bieng destroyed - deactivate any modes that were active for this toolkit
for ( auto ToolkitIt = ActiveToolkits . CreateConstIterator ( ) ; ToolkitIt ; + + ToolkitIt )
{
( * ToolkitIt ) - > DeactivateMode ( ) ;
}
// Unregister delegates
2014-06-18 10:16:16 -04:00
GLevelEditorModeTools ( ) . OnEditorModeChanged ( ) . RemoveAll ( this ) ;
2014-03-14 14:13:41 -04:00
}
void SToolkitDisplay : : AddEditorMode ( FEdMode * EditorMode )
{
// @todo toolkit major: should we move these somewhere where they won't get covered up by world-centric! (tool bar? perma-tab? viewport overlay?)
TSharedRef < SLevelEditorActiveToolkit > NewActiveToolkit =
SNew ( SLevelEditorActiveToolkit , TSharedPtr < IToolkit > ( ) , EditorMode ) ;
ActiveToolkits . Add ( NewActiveToolkit ) ;
VBox - > AddSlot ( )
. AutoHeight ( )
[
NewActiveToolkit
] ;
}
void SToolkitDisplay : : RemoveEditorMode ( FEdMode * EditorMode )
{
for ( auto ToolkitIt = ActiveToolkits . CreateConstIterator ( ) ; ToolkitIt ; + + ToolkitIt )
{
if ( ( * ToolkitIt ) - > EditorMode = = EditorMode )
{
// Remove this widget!
VBox - > RemoveSlot ( ToolkitIt - > ToSharedRef ( ) ) ;
ActiveToolkits . RemoveAt ( ToolkitIt . GetIndex ( ) ) ;
break ;
}
}
}
void SToolkitDisplay : : OnEditorModeChanged ( FEdMode * EditorMode , bool bEntered )
{
check ( EditorMode ! = NULL ) ;
// @todo toolkit minor: Really, we should only be listening about editor modes that are related to the SLevelEditor's world!
// We don't care about the default editor mode. Just ignore it.
if ( EditorMode - > GetID ( ) ! = FBuiltinEditorModes : : EM_Default & & ! EditorMode - > UsesToolkits ( ) )
{
if ( bEntered )
{
AddEditorMode ( EditorMode ) ;
}
else
{
RemoveEditorMode ( EditorMode ) ;
}
}
}
void SToolkitDisplay : : AddToolkit ( const TSharedRef < IToolkit > & NewToolkit )
{
TSharedRef < SLevelEditorActiveToolkit > NewActiveToolkit =
SNew ( SLevelEditorActiveToolkit , NewToolkit , ( FEdMode * ) NULL ) ;
ActiveToolkits . Add ( NewActiveToolkit ) ;
VBox - > AddSlot ( )
. AutoHeight ( )
[
NewActiveToolkit
] ;
}
void SToolkitDisplay : : RemoveToolkit ( const TSharedRef < IToolkit > & DestroyingToolkit )
{
for ( auto ToolkitIt = ActiveToolkits . CreateConstIterator ( ) ; ToolkitIt ; + + ToolkitIt )
{
if ( ( * ToolkitIt ) - > Toolkit = = DestroyingToolkit )
{
// Remove this widget!
VBox - > RemoveSlot ( ToolkitIt - > ToSharedRef ( ) ) ;
ActiveToolkits . RemoveAt ( ToolkitIt . GetIndex ( ) ) ;
break ;
}
}
}
void SToolkitDisplay : : OnToolkitHostingStarted ( const TSharedRef < IToolkit > & NewToolkit )
{
if ( NewToolkit - > GetEditorMode ( ) )
{
AddEditorMode ( NewToolkit - > GetEditorMode ( ) ) ;
OnInlineContentChangedDelegate . ExecuteIfBound ( NewToolkit - > GetInlineContent ( ) . ToSharedRef ( ) ) ;
}
else
{
AddToolkit ( NewToolkit ) ;
}
}
void SToolkitDisplay : : OnToolkitHostingFinished ( const TSharedRef < IToolkit > & DestroyingToolkit )
{
if ( DestroyingToolkit - > GetEditorMode ( ) )
{
RemoveEditorMode ( DestroyingToolkit - > GetEditorMode ( ) ) ;
OnInlineContentChangedDelegate . ExecuteIfBound ( SNullWidget : : NullWidget ) ;
}
else
{
RemoveToolkit ( DestroyingToolkit ) ;
}
}
# undef LOCTEXT_NAMESPACE