2016-12-08 08:52:44 -05:00
// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved.
2014-03-14 14:13:41 -04:00
# include "SGraphEditorImpl.h"
Copying //UE4/Dev-Build to //UE4/Dev-Main (Source: //UE4/Dev-Build @ 3209340)
#lockdown Nick.Penwarden
#rb none
==========================
MAJOR FEATURES + CHANGES
==========================
Change 3209340 on 2016/11/23 by Ben.Marsh
Convert UE4 codebase to an "include what you use" model - where every header just includes the dependencies it needs, rather than every source file including large monolithic headers like Engine.h and UnrealEd.h.
Measured full rebuild times around 2x faster using XGE on Windows, and improvements of 25% or more for incremental builds and full rebuilds on most other platforms.
* Every header now includes everything it needs to compile.
* There's a CoreMinimal.h header that gets you a set of ubiquitous types from Core (eg. FString, FName, TArray, FVector, etc...). Most headers now include this first.
* There's a CoreTypes.h header that sets up primitive UE4 types and build macros (int32, PLATFORM_WIN64, etc...). All headers in Core include this first, as does CoreMinimal.h.
* Every .cpp file includes its matching .h file first.
* This helps validate that each header is including everything it needs to compile.
* No engine code includes a monolithic header such as Engine.h or UnrealEd.h any more.
* You will get a warning if you try to include one of these from the engine. They still exist for compatibility with game projects and do not produce warnings when included there.
* There have only been minor changes to our internal games down to accommodate these changes. The intent is for this to be as seamless as possible.
* No engine code explicitly includes a precompiled header any more.
* We still use PCHs, but they're force-included on the compiler command line by UnrealBuildTool instead. This lets us tune what they contain without breaking any existing include dependencies.
* PCHs are generated by a tool to get a statistical amount of coverage for the source files using it, and I've seeded the new shared PCHs to contain any header included by > 15% of source files.
Tool used to generate this transform is at Engine\Source\Programs\IncludeTool.
[CL 3209342 by Ben Marsh in Main branch]
2016-11-23 15:48:37 -05:00
# include "GraphEditAction.h"
# include "EdGraph/EdGraph.h"
# include "Modules/ModuleManager.h"
# include "Widgets/SBoxPanel.h"
# include "Framework/Application/SlateApplication.h"
# include "Widgets/Layout/SBorder.h"
# include "Widgets/Text/STextBlock.h"
# include "Framework/MultiBox/MultiBoxExtender.h"
# include "Framework/MultiBox/MultiBoxBuilder.h"
# include "EditorStyleSet.h"
# include "Editor.h"
2014-03-14 14:13:41 -04:00
# include "GraphEditorModule.h"
2014-10-14 22:50:06 -04:00
# include "SGraphPanel.h"
Copying //UE4/Dev-Build to //UE4/Dev-Main (Source: //UE4/Dev-Build @ 3209340)
#lockdown Nick.Penwarden
#rb none
==========================
MAJOR FEATURES + CHANGES
==========================
Change 3209340 on 2016/11/23 by Ben.Marsh
Convert UE4 codebase to an "include what you use" model - where every header just includes the dependencies it needs, rather than every source file including large monolithic headers like Engine.h and UnrealEd.h.
Measured full rebuild times around 2x faster using XGE on Windows, and improvements of 25% or more for incremental builds and full rebuilds on most other platforms.
* Every header now includes everything it needs to compile.
* There's a CoreMinimal.h header that gets you a set of ubiquitous types from Core (eg. FString, FName, TArray, FVector, etc...). Most headers now include this first.
* There's a CoreTypes.h header that sets up primitive UE4 types and build macros (int32, PLATFORM_WIN64, etc...). All headers in Core include this first, as does CoreMinimal.h.
* Every .cpp file includes its matching .h file first.
* This helps validate that each header is including everything it needs to compile.
* No engine code includes a monolithic header such as Engine.h or UnrealEd.h any more.
* You will get a warning if you try to include one of these from the engine. They still exist for compatibility with game projects and do not produce warnings when included there.
* There have only been minor changes to our internal games down to accommodate these changes. The intent is for this to be as seamless as possible.
* No engine code explicitly includes a precompiled header any more.
* We still use PCHs, but they're force-included on the compiler command line by UnrealBuildTool instead. This lets us tune what they contain without breaking any existing include dependencies.
* PCHs are generated by a tool to get a statistical amount of coverage for the source files using it, and I've seeded the new shared PCHs to contain any header included by > 15% of source files.
Tool used to generate this transform is at Engine\Source\Programs\IncludeTool.
[CL 3209342 by Ben Marsh in Main branch]
2016-11-23 15:48:37 -05:00
# include "GraphEditorActions.h"
# include "ScopedTransaction.h"
# include "SGraphEditorActionMenu.h"
# include "Widgets/Notifications/SNotificationList.h"
2014-03-14 14:13:41 -04:00
# define LOCTEXT_NAMESPACE "GraphEditorModule"
/////////////////////////////////////////////////////
// SGraphEditorImpl
FVector2D SGraphEditorImpl : : GetPasteLocation ( ) const
{
return GraphPanel - > GetPastePosition ( ) ;
}
bool SGraphEditorImpl : : IsNodeTitleVisible ( const UEdGraphNode * Node , bool bEnsureVisible )
{
return GraphPanel - > IsNodeTitleVisible ( Node , bEnsureVisible ) ;
}
2015-05-01 06:38:56 -04:00
void SGraphEditorImpl : : JumpToNode ( const UEdGraphNode * JumpToMe , bool bRequestRename , bool bSelectNode )
2014-03-14 14:13:41 -04:00
{
2015-05-01 06:38:56 -04:00
GraphPanel - > JumpToNode ( JumpToMe , bRequestRename , bSelectNode ) ;
2014-03-14 14:13:41 -04:00
FocusLockedEditorHere ( ) ;
}
void SGraphEditorImpl : : JumpToPin ( const UEdGraphPin * JumpToMe )
{
GraphPanel - > JumpToPin ( JumpToMe ) ;
FocusLockedEditorHere ( ) ;
}
bool SGraphEditorImpl : : SupportsKeyboardFocus ( ) const
{
return true ;
}
2014-10-30 12:29:36 -04:00
FReply SGraphEditorImpl : : OnFocusReceived ( const FGeometry & MyGeometry , const FFocusEvent & InFocusEvent )
2014-03-14 14:13:41 -04:00
{
OnFocused . ExecuteIfBound ( SharedThis ( this ) ) ;
return FReply : : Handled ( ) ;
}
FReply SGraphEditorImpl : : OnMouseButtonDown ( const FGeometry & MyGeometry , const FPointerEvent & MouseEvent )
{
if ( MouseEvent . IsMouseButtonDown ( EKeys : : ThumbMouseButton ) )
{
OnNavigateHistoryBack . ExecuteIfBound ( ) ;
}
else if ( MouseEvent . IsMouseButtonDown ( EKeys : : ThumbMouseButton2 ) )
{
OnNavigateHistoryForward . ExecuteIfBound ( ) ;
}
2014-10-30 12:29:36 -04:00
return FReply : : Handled ( ) . SetUserFocus ( SharedThis ( this ) , EFocusCause : : Mouse ) ;
2014-03-14 14:13:41 -04:00
}
2014-10-30 12:29:36 -04:00
FReply SGraphEditorImpl : : OnKeyDown ( const FGeometry & MyGeometry , const FKeyEvent & InKeyEvent )
2014-03-14 14:13:41 -04:00
{
int32 NumNodes = GetCurrentGraph ( ) - > Nodes . Num ( ) ;
2014-10-30 12:29:36 -04:00
if ( Commands - > ProcessCommandBindings ( InKeyEvent ) )
2014-03-14 14:13:41 -04:00
{
2014-10-30 12:29:36 -04:00
bool bPasteOperation = InKeyEvent . IsControlDown ( ) & & InKeyEvent . GetKey ( ) = = EKeys : : V ;
2014-03-14 14:13:41 -04:00
if ( ! bPasteOperation & & GetCurrentGraph ( ) - > Nodes . Num ( ) > NumNodes )
{
OnNodeSpawnedByKeymap . ExecuteIfBound ( ) ;
}
return FReply : : Handled ( ) ;
}
else
{
2014-10-30 12:29:36 -04:00
return SCompoundWidget : : OnKeyDown ( MyGeometry , InKeyEvent ) ;
2014-03-14 14:13:41 -04:00
}
}
void SGraphEditorImpl : : NotifyGraphChanged ( )
{
FEdGraphEditAction DefaultAction ;
OnGraphChanged ( DefaultAction ) ;
}
void SGraphEditorImpl : : OnGraphChanged ( const FEdGraphEditAction & InAction )
{
2015-01-20 14:04:44 -05:00
if ( ! bIsActiveTimerRegistered )
2014-03-14 14:13:41 -04:00
{
2015-01-21 23:54:10 -05:00
const UEdGraphSchema * Schema = EdGraphObj - > GetSchema ( ) ;
2015-01-22 13:35:22 -05:00
const bool bSchemaRequiresFullRefresh = Schema - > ShouldAlwaysPurgeOnModification ( ) ;
const bool bWasAddAction = ( InAction . Action & GRAPHACTION_AddNode ) ! = 0 ;
const bool bWasSelectAction = ( InAction . Action & GRAPHACTION_SelectNode ) ! = 0 ;
const bool bWasRemoveAction = ( InAction . Action & GRAPHACTION_RemoveNode ) ! = 0 ;
// If we did a 'default action' (or some other action not handled by SGraphPanel::OnGraphChanged
// or if we're using a schema that always needs a full refresh, then purge the current nodes
// and queue an update:
if ( bSchemaRequiresFullRefresh | |
( ! bWasAddAction & & ! bWasSelectAction & & ! bWasRemoveAction ) )
2015-01-21 23:54:10 -05:00
{
GraphPanel - > PurgeVisualRepresentation ( ) ;
// Trigger the refresh
bIsActiveTimerRegistered = true ;
RegisterActiveTimer ( 0.f , FWidgetActiveTimerDelegate : : CreateSP ( this , & SGraphEditorImpl : : TriggerRefresh ) ) ;
}
2014-03-14 14:13:41 -04:00
}
}
---- Merging with SlateDev branch ----
Introduces the concept of "Active Ticking" to allow Slate to go to sleep when there is no need to update the UI.
While asleep, Slate will skip the Tick & Paint pass for that frame entirely.
- There are TWO ways to "wake" Slate and cause a Tick/Paint pass:
1. Provide some sort of input (mouse movement, clicks, and key presses). Slate will always tick when the user is active.
- Therefore, if the logic in a given widget's Tick is only relevant in response to user action, there is no need to register an active tick.
2. Register an Active Tick. Currently this is an all-or-nothing situation, so if a single active tick needs to execute, all of Slate will be ticked.
- The purpose of an Active Tick is to allow a widget to "drive" Slate and guarantee a Tick/Paint pass in the absence of any user action.
- Examples include animation, async operations that update periodically, progress updates, loading bars, etc.
- An empty active tick is registered for viewports when they are real-time, so game project widgets are unaffected by this change and should continue to work as before.
- An Active Tick is registered by creating an FWidgetActiveTickDelegate and passing it to SWidget::RegisterActiveTick()
- There are THREE ways to unregister an active tick:
1. Return EActiveTickReturnType::StopTicking from the active tick function
2. Pass the FActiveTickHandle returned by RegisterActiveTick() to SWidget::UnregisterActiveTick()
3. Destroy the widget responsible for the active tick
- Sleeping is currently disabled, can be enabled with Slate.AllowSlateToSleep cvar
- There is currently a little buffer time during which Slate continues to tick following any input. Long-term, this is planned to be removed.
- The duration of the buffer can be adjusted using Slate.SleepBufferPostInput cvar (defaults to 1.0f)
- The FCurveSequence API has been updated to work with the active tick system
- Playing a curve sequence now requires that you pass the widget being animated by the sequence
- The active tick will automatically be registered on behalf of the widget and unregister when the sequence is complete
- GetLerpLooping() has been removed. Instead, pass true as the second param to Play() to indicate that the animation will loop. This causes the active tick to be registered indefinitely until paused or jumped to the start/end.
[CL 2391669 by Dan Hertzka in Main branch]
2014-12-17 16:07:57 -05:00
//void SGraphEditorImpl::GraphEd_OnPanelUpdated()
//{
//
//}
2014-03-14 14:13:41 -04:00
const TSet < class UObject * > & SGraphEditorImpl : : GetSelectedNodes ( ) const
{
return GraphPanel - > SelectionManager . GetSelectedNodes ( ) ;
}
void SGraphEditorImpl : : ClearSelectionSet ( )
{
GraphPanel - > SelectionManager . ClearSelectionSet ( ) ;
}
void SGraphEditorImpl : : SetNodeSelection ( UEdGraphNode * Node , bool bSelect )
{
GraphPanel - > SelectionManager . SetNodeSelection ( Node , bSelect ) ;
}
void SGraphEditorImpl : : SelectAllNodes ( )
{
FGraphPanelSelectionSet NewSet ;
for ( int32 NodeIndex = 0 ; NodeIndex < EdGraphObj - > Nodes . Num ( ) ; + + NodeIndex )
{
UEdGraphNode * Node = EdGraphObj - > Nodes [ NodeIndex ] ;
2015-05-13 15:31:46 -04:00
if ( Node )
{
2015-07-10 05:31:32 -04:00
ensureMsgf ( Node - > IsValidLowLevel ( ) , TEXT ( " Node is invalid " ) ) ;
2015-05-13 15:31:46 -04:00
NewSet . Add ( Node ) ;
}
2014-03-14 14:13:41 -04:00
}
GraphPanel - > SelectionManager . SetSelectionSet ( NewSet ) ;
}
UEdGraphPin * SGraphEditorImpl : : GetGraphPinForMenu ( )
{
return GraphPinForMenu ;
}
2015-09-14 05:47:07 -04:00
UEdGraphNode * SGraphEditorImpl : : GetGraphNodeForMenu ( )
{
return GraphNodeForMenu ;
}
2014-03-14 14:13:41 -04:00
void SGraphEditorImpl : : ZoomToFit ( bool bOnlySelection )
{
GraphPanel - > ZoomToFit ( bOnlySelection ) ;
}
bool SGraphEditorImpl : : GetBoundsForSelectedNodes ( class FSlateRect & Rect , float Padding )
{
return GraphPanel - > GetBoundsForSelectedNodes ( Rect , Padding ) ;
}
2015-08-14 09:34:31 -04:00
bool SGraphEditorImpl : : GetBoundsForNode ( const UEdGraphNode * InNode , class FSlateRect & Rect , float Padding ) const
{
FVector2D TopLeft , BottomRight ;
if ( GraphPanel - > GetBoundsForNode ( InNode , TopLeft , BottomRight , Padding ) )
{
Rect . Left = TopLeft . X ;
Rect . Top = TopLeft . Y ;
Rect . Bottom = BottomRight . Y ;
Rect . Right = BottomRight . X ;
return true ;
}
return false ;
}
2015-09-14 05:47:07 -04:00
void SGraphEditorImpl : : StraightenConnections ( )
{
GraphPanel - > StraightenConnections ( ) ;
}
void SGraphEditorImpl : : StraightenConnections ( UEdGraphPin * SourcePin , UEdGraphPin * PinToAlign )
{
GraphPanel - > StraightenConnections ( SourcePin , PinToAlign ) ;
}
2014-03-14 14:13:41 -04:00
void SGraphEditorImpl : : Construct ( const FArguments & InArgs )
{
Commands = MakeShareable ( new FUICommandList ( ) ) ;
IsEditable = InArgs . _IsEditable ;
2015-05-07 12:39:59 -04:00
DisplayAsReadOnly = InArgs . _DisplayAsReadOnly ;
2014-03-14 14:13:41 -04:00
Appearance = InArgs . _Appearance ;
TitleBar = InArgs . _TitleBar ;
bAutoExpandActionMenu = InArgs . _AutoExpandActionMenu ;
2014-06-09 11:12:17 -04:00
ShowGraphStateOverlay = InArgs . _ShowGraphStateOverlay ;
2014-03-14 14:13:41 -04:00
OnNavigateHistoryBack = InArgs . _OnNavigateHistoryBack ;
OnNavigateHistoryForward = InArgs . _OnNavigateHistoryForward ;
OnNodeSpawnedByKeymap = InArgs . _GraphEvents . OnNodeSpawnedByKeymap ;
2014-12-19 17:44:49 -05:00
bIsActiveTimerRegistered = false ;
---- Merging with SlateDev branch ----
Introduces the concept of "Active Ticking" to allow Slate to go to sleep when there is no need to update the UI.
While asleep, Slate will skip the Tick & Paint pass for that frame entirely.
- There are TWO ways to "wake" Slate and cause a Tick/Paint pass:
1. Provide some sort of input (mouse movement, clicks, and key presses). Slate will always tick when the user is active.
- Therefore, if the logic in a given widget's Tick is only relevant in response to user action, there is no need to register an active tick.
2. Register an Active Tick. Currently this is an all-or-nothing situation, so if a single active tick needs to execute, all of Slate will be ticked.
- The purpose of an Active Tick is to allow a widget to "drive" Slate and guarantee a Tick/Paint pass in the absence of any user action.
- Examples include animation, async operations that update periodically, progress updates, loading bars, etc.
- An empty active tick is registered for viewports when they are real-time, so game project widgets are unaffected by this change and should continue to work as before.
- An Active Tick is registered by creating an FWidgetActiveTickDelegate and passing it to SWidget::RegisterActiveTick()
- There are THREE ways to unregister an active tick:
1. Return EActiveTickReturnType::StopTicking from the active tick function
2. Pass the FActiveTickHandle returned by RegisterActiveTick() to SWidget::UnregisterActiveTick()
3. Destroy the widget responsible for the active tick
- Sleeping is currently disabled, can be enabled with Slate.AllowSlateToSleep cvar
- There is currently a little buffer time during which Slate continues to tick following any input. Long-term, this is planned to be removed.
- The duration of the buffer can be adjusted using Slate.SleepBufferPostInput cvar (defaults to 1.0f)
- The FCurveSequence API has been updated to work with the active tick system
- Playing a curve sequence now requires that you pass the widget being animated by the sequence
- The active tick will automatically be registered on behalf of the widget and unregister when the sequence is complete
- GetLerpLooping() has been removed. Instead, pass true as the second param to Play() to indicate that the animation will loop. This causes the active tick to be registered indefinitely until paused or jumped to the start/end.
[CL 2391669 by Dan Hertzka in Main branch]
2014-12-17 16:07:57 -05:00
2014-03-14 14:13:41 -04:00
// Make sure that the editor knows about what kinds
// of commands GraphEditor can do.
FGraphEditorCommands : : Register ( ) ;
// Tell GraphEditor how to handle all the known commands
{
Commands - > MapAction ( FGraphEditorCommands : : Get ( ) . ReconstructNodes ,
FExecuteAction : : CreateSP ( this , & SGraphEditorImpl : : ReconstructNodes ) ,
FCanExecuteAction : : CreateSP ( this , & SGraphEditorImpl : : CanReconstructNodes )
) ;
Commands - > MapAction ( FGraphEditorCommands : : Get ( ) . BreakNodeLinks ,
FExecuteAction : : CreateSP ( this , & SGraphEditorImpl : : BreakNodeLinks ) ,
FCanExecuteAction : : CreateSP ( this , & SGraphEditorImpl : : CanBreakNodeLinks )
) ;
Commands - > MapAction ( FGraphEditorCommands : : Get ( ) . BreakPinLinks ,
FExecuteAction : : CreateSP ( this , & SGraphEditorImpl : : BreakPinLinks , true ) ,
FCanExecuteAction : : CreateSP ( this , & SGraphEditorImpl : : CanBreakPinLinks )
) ;
// Append any additional commands that a consumer of GraphEditor wants us to be aware of.
const TSharedPtr < FUICommandList > & AdditionalCommands = InArgs . _AdditionalCommands ;
if ( AdditionalCommands . IsValid ( ) )
{
Commands - > Append ( AdditionalCommands . ToSharedRef ( ) ) ;
}
}
GraphPinForMenu = NULL ;
EdGraphObj = InArgs . _GraphToEdit ;
---- Merging with SlateDev branch ----
Introduces the concept of "Active Ticking" to allow Slate to go to sleep when there is no need to update the UI.
While asleep, Slate will skip the Tick & Paint pass for that frame entirely.
- There are TWO ways to "wake" Slate and cause a Tick/Paint pass:
1. Provide some sort of input (mouse movement, clicks, and key presses). Slate will always tick when the user is active.
- Therefore, if the logic in a given widget's Tick is only relevant in response to user action, there is no need to register an active tick.
2. Register an Active Tick. Currently this is an all-or-nothing situation, so if a single active tick needs to execute, all of Slate will be ticked.
- The purpose of an Active Tick is to allow a widget to "drive" Slate and guarantee a Tick/Paint pass in the absence of any user action.
- Examples include animation, async operations that update periodically, progress updates, loading bars, etc.
- An empty active tick is registered for viewports when they are real-time, so game project widgets are unaffected by this change and should continue to work as before.
- An Active Tick is registered by creating an FWidgetActiveTickDelegate and passing it to SWidget::RegisterActiveTick()
- There are THREE ways to unregister an active tick:
1. Return EActiveTickReturnType::StopTicking from the active tick function
2. Pass the FActiveTickHandle returned by RegisterActiveTick() to SWidget::UnregisterActiveTick()
3. Destroy the widget responsible for the active tick
- Sleeping is currently disabled, can be enabled with Slate.AllowSlateToSleep cvar
- There is currently a little buffer time during which Slate continues to tick following any input. Long-term, this is planned to be removed.
- The duration of the buffer can be adjusted using Slate.SleepBufferPostInput cvar (defaults to 1.0f)
- The FCurveSequence API has been updated to work with the active tick system
- Playing a curve sequence now requires that you pass the widget being animated by the sequence
- The active tick will automatically be registered on behalf of the widget and unregister when the sequence is complete
- GetLerpLooping() has been removed. Instead, pass true as the second param to Play() to indicate that the animation will loop. This causes the active tick to be registered indefinitely until paused or jumped to the start/end.
[CL 2391669 by Dan Hertzka in Main branch]
2014-12-17 16:07:57 -05:00
2014-03-14 14:13:41 -04:00
OnFocused = InArgs . _GraphEvents . OnFocused ;
OnCreateActionMenu = InArgs . _GraphEvents . OnCreateActionMenu ;
struct Local
{
2015-01-07 09:52:40 -05:00
static FText GetPIENotifyText ( TAttribute < FGraphAppearanceInfo > Appearance , FText DefaultText )
2014-03-14 14:13:41 -04:00
{
2015-01-07 09:52:40 -05:00
FText OverrideText = Appearance . Get ( ) . PIENotifyText ;
return ! OverrideText . IsEmpty ( ) ? OverrideText : DefaultText ;
2014-03-14 14:13:41 -04:00
}
2014-05-01 05:32:30 -04:00
2015-01-07 09:52:40 -05:00
static FText GetReadOnlyText ( TAttribute < FGraphAppearanceInfo > Appearance , FText DefaultText )
2014-05-01 05:32:30 -04:00
{
2015-01-07 09:52:40 -05:00
FText OverrideText = Appearance . Get ( ) . ReadOnlyText ;
return ! OverrideText . IsEmpty ( ) ? OverrideText : DefaultText ;
2014-05-01 05:32:30 -04:00
}
2014-03-14 14:13:41 -04:00
} ;
2015-01-07 09:52:40 -05:00
FText DefaultPIENotify ( LOCTEXT ( " GraphSimulatingText " , " SIMULATING " ) ) ;
TAttribute < FText > PIENotifyText = Appearance . IsBound ( ) ?
TAttribute < FText > : : Create ( TAttribute < FText > : : FGetter : : CreateStatic ( & Local : : GetPIENotifyText , Appearance , DefaultPIENotify ) ) :
TAttribute < FText > ( DefaultPIENotify ) ;
2014-03-14 14:13:41 -04:00
2015-01-07 09:52:40 -05:00
FText DefaultReadOnlyText ( LOCTEXT ( " GraphReadOnlyText " , " READ-ONLY " ) ) ;
TAttribute < FText > ReadOnlyText = Appearance . IsBound ( ) ?
TAttribute < FText > : : Create ( TAttribute < FText > : : FGetter : : CreateStatic ( & Local : : GetReadOnlyText , Appearance , DefaultReadOnlyText ) ) :
TAttribute < FText > ( DefaultReadOnlyText ) ;
2014-05-01 05:32:30 -04:00
2014-03-14 14:13:41 -04:00
TSharedPtr < SOverlay > OverlayWidget ;
this - > ChildSlot
[
SAssignNew ( OverlayWidget , SOverlay )
// The graph panel
+ SOverlay : : Slot ( )
. Expose ( GraphPanelSlot )
[
SAssignNew ( GraphPanel , SGraphPanel )
. GraphObj ( EdGraphObj )
. GraphObjToDiff ( InArgs . _GraphToDiff )
. OnGetContextMenuFor ( this , & SGraphEditorImpl : : GraphEd_OnGetContextMenuFor )
. OnSelectionChanged ( InArgs . _GraphEvents . OnSelectionChanged )
. OnNodeDoubleClicked ( InArgs . _GraphEvents . OnNodeDoubleClicked )
2014-05-01 05:32:30 -04:00
. IsEditable ( this , & SGraphEditorImpl : : IsGraphEditable )
2015-05-07 12:39:59 -04:00
. DisplayAsReadOnly ( this , & SGraphEditorImpl : : DisplayGraphAsReadOnly )
2014-03-14 14:13:41 -04:00
. OnDropActor ( InArgs . _GraphEvents . OnDropActor )
. OnDropStreamingLevel ( InArgs . _GraphEvents . OnDropStreamingLevel )
. OnVerifyTextCommit ( InArgs . _GraphEvents . OnVerifyTextCommit )
. OnTextCommitted ( InArgs . _GraphEvents . OnTextCommitted )
. OnSpawnNodeByShortcut ( InArgs . _GraphEvents . OnSpawnNodeByShortcut )
---- Merging with SlateDev branch ----
Introduces the concept of "Active Ticking" to allow Slate to go to sleep when there is no need to update the UI.
While asleep, Slate will skip the Tick & Paint pass for that frame entirely.
- There are TWO ways to "wake" Slate and cause a Tick/Paint pass:
1. Provide some sort of input (mouse movement, clicks, and key presses). Slate will always tick when the user is active.
- Therefore, if the logic in a given widget's Tick is only relevant in response to user action, there is no need to register an active tick.
2. Register an Active Tick. Currently this is an all-or-nothing situation, so if a single active tick needs to execute, all of Slate will be ticked.
- The purpose of an Active Tick is to allow a widget to "drive" Slate and guarantee a Tick/Paint pass in the absence of any user action.
- Examples include animation, async operations that update periodically, progress updates, loading bars, etc.
- An empty active tick is registered for viewports when they are real-time, so game project widgets are unaffected by this change and should continue to work as before.
- An Active Tick is registered by creating an FWidgetActiveTickDelegate and passing it to SWidget::RegisterActiveTick()
- There are THREE ways to unregister an active tick:
1. Return EActiveTickReturnType::StopTicking from the active tick function
2. Pass the FActiveTickHandle returned by RegisterActiveTick() to SWidget::UnregisterActiveTick()
3. Destroy the widget responsible for the active tick
- Sleeping is currently disabled, can be enabled with Slate.AllowSlateToSleep cvar
- There is currently a little buffer time during which Slate continues to tick following any input. Long-term, this is planned to be removed.
- The duration of the buffer can be adjusted using Slate.SleepBufferPostInput cvar (defaults to 1.0f)
- The FCurveSequence API has been updated to work with the active tick system
- Playing a curve sequence now requires that you pass the widget being animated by the sequence
- The active tick will automatically be registered on behalf of the widget and unregister when the sequence is complete
- GetLerpLooping() has been removed. Instead, pass true as the second param to Play() to indicate that the animation will loop. This causes the active tick to be registered indefinitely until paused or jumped to the start/end.
[CL 2391669 by Dan Hertzka in Main branch]
2014-12-17 16:07:57 -05:00
//.OnUpdateGraphPanel( this, &SGraphEditorImpl::GraphEd_OnPanelUpdated )
2014-03-14 14:13:41 -04:00
. OnDisallowedPinConnection ( InArgs . _GraphEvents . OnDisallowedPinConnection )
2014-06-09 11:12:17 -04:00
. ShowGraphStateOverlay ( InArgs . _ShowGraphStateOverlay )
2014-03-14 14:13:41 -04:00
]
// Indicator of current zoom level
+ SOverlay : : Slot ( )
. Padding ( 5 )
. VAlign ( VAlign_Top )
. HAlign ( HAlign_Right )
[
SNew ( STextBlock )
. TextStyle ( FEditorStyle : : Get ( ) , " Graph.ZoomText " )
. Text ( this , & SGraphEditorImpl : : GetZoomText )
. ColorAndOpacity ( this , & SGraphEditorImpl : : GetZoomTextColorAndOpacity )
]
// Title bar - optional
+ SOverlay : : Slot ( )
. VAlign ( VAlign_Top )
[
2014-09-12 18:42:03 -04:00
SNew ( SVerticalBox )
+ SVerticalBox : : Slot ( )
[
InArgs . _TitleBar . IsValid ( ) ? InArgs . _TitleBar . ToSharedRef ( ) : ( TSharedRef < SWidget > ) SNullWidget : : NullWidget
]
+ SVerticalBox : : Slot ( )
. Padding ( 20.f , 20.f , 20.f , 0.f )
. VAlign ( VAlign_Top )
. HAlign ( HAlign_Center )
. AutoHeight ( )
[
SNew ( SBorder )
. Padding ( FMargin ( 10.f , 4.f ) )
. BorderImage ( FEditorStyle : : GetBrush ( TEXT ( " Graph.InstructionBackground " ) ) )
. BorderBackgroundColor ( this , & SGraphEditorImpl : : InstructionBorderColor )
. HAlign ( HAlign_Center )
. ColorAndOpacity ( this , & SGraphEditorImpl : : InstructionTextTint )
. Visibility ( this , & SGraphEditorImpl : : InstructionTextVisibility )
[
SNew ( STextBlock )
. TextStyle ( FEditorStyle : : Get ( ) , " Graph.InstructionText " )
. Text ( this , & SGraphEditorImpl : : GetInstructionText )
]
]
2014-03-14 14:13:41 -04:00
]
// Bottom-right corner text indicating the type of tool
+ SOverlay : : Slot ( )
. Padding ( 10 )
. VAlign ( VAlign_Bottom )
. HAlign ( HAlign_Right )
[
SNew ( STextBlock )
. Visibility ( EVisibility : : HitTestInvisible )
. TextStyle ( FEditorStyle : : Get ( ) , " Graph.CornerText " )
. Text ( Appearance . Get ( ) . CornerText )
]
// Top-right corner text indicating PIE is active
+ SOverlay : : Slot ( )
. Padding ( 20 )
. VAlign ( VAlign_Top )
. HAlign ( HAlign_Right )
[
SNew ( STextBlock )
. Visibility ( this , & SGraphEditorImpl : : PIENotification )
. TextStyle ( FEditorStyle : : Get ( ) , " Graph.SimulatingText " )
. Text ( PIENotifyText )
]
2014-05-01 05:32:30 -04:00
// Top-right corner text indicating read only when not simulating
+ SOverlay : : Slot ( )
. Padding ( 20 )
. VAlign ( VAlign_Top )
. HAlign ( HAlign_Right )
[
SNew ( STextBlock )
. Visibility ( this , & SGraphEditorImpl : : ReadOnlyVisibility )
. TextStyle ( FEditorStyle : : Get ( ) , " Graph.CornerText " )
. Text ( ReadOnlyText )
]
2014-09-12 18:42:03 -04:00
// + SOverlay::Slot()
// .Padding(20)
// .VAlign(VAlign_Fill)
// .HAlign(HAlign_Fill)
// [
// SNew(SVerticalBox)
// + SVerticalBox::Slot()
// .FillHeight(0.5)
// .VAlign(VAlign_Bottom)
// .HAlign(HAlign_Center)
// [
//
// ]
// + SVerticalBox::Slot()
// .FillHeight(0.5)
// ]
2014-03-14 14:13:41 -04:00
// Bottom-right corner text for notification list position
+ SOverlay : : Slot ( )
. Padding ( 15.f )
. VAlign ( VAlign_Bottom )
. HAlign ( HAlign_Right )
[
SAssignNew ( NotificationListPtr , SNotificationList )
. Visibility ( EVisibility : : HitTestInvisible )
]
] ;
GraphPanel - > RestoreViewSettings ( FVector2D : : ZeroVector , - 1 ) ;
NotifyGraphChanged ( ) ;
}
EVisibility SGraphEditorImpl : : PIENotification ( ) const
{
2014-06-09 11:12:17 -04:00
if ( ShowGraphStateOverlay . Get ( ) & & ( GEditor - > bIsSimulatingInEditor | | GEditor - > PlayWorld ! = NULL ) )
2014-03-14 14:13:41 -04:00
{
return EVisibility : : Visible ;
}
return EVisibility : : Hidden ;
}
SGraphEditorImpl : : ~ SGraphEditorImpl ( )
{
}
void SGraphEditorImpl : : Tick ( const FGeometry & AllottedGeometry , const double InCurrentTime , const float InDeltaTime )
{
// If locked to another graph editor, and our panel has moved, synchronise the locked graph editor accordingly
if ( ( EdGraphObj ! = NULL ) & & GraphPanel . IsValid ( ) )
{
2014-06-04 20:07:21 -04:00
if ( GraphPanel - > HasMoved ( ) & & IsLocked ( ) )
2014-03-14 14:13:41 -04:00
{
FocusLockedEditorHere ( ) ;
}
}
}
2014-12-19 17:44:49 -05:00
EActiveTimerReturnType SGraphEditorImpl : : TriggerRefresh ( double InCurrentTime , float InDeltaTime )
---- Merging with SlateDev branch ----
Introduces the concept of "Active Ticking" to allow Slate to go to sleep when there is no need to update the UI.
While asleep, Slate will skip the Tick & Paint pass for that frame entirely.
- There are TWO ways to "wake" Slate and cause a Tick/Paint pass:
1. Provide some sort of input (mouse movement, clicks, and key presses). Slate will always tick when the user is active.
- Therefore, if the logic in a given widget's Tick is only relevant in response to user action, there is no need to register an active tick.
2. Register an Active Tick. Currently this is an all-or-nothing situation, so if a single active tick needs to execute, all of Slate will be ticked.
- The purpose of an Active Tick is to allow a widget to "drive" Slate and guarantee a Tick/Paint pass in the absence of any user action.
- Examples include animation, async operations that update periodically, progress updates, loading bars, etc.
- An empty active tick is registered for viewports when they are real-time, so game project widgets are unaffected by this change and should continue to work as before.
- An Active Tick is registered by creating an FWidgetActiveTickDelegate and passing it to SWidget::RegisterActiveTick()
- There are THREE ways to unregister an active tick:
1. Return EActiveTickReturnType::StopTicking from the active tick function
2. Pass the FActiveTickHandle returned by RegisterActiveTick() to SWidget::UnregisterActiveTick()
3. Destroy the widget responsible for the active tick
- Sleeping is currently disabled, can be enabled with Slate.AllowSlateToSleep cvar
- There is currently a little buffer time during which Slate continues to tick following any input. Long-term, this is planned to be removed.
- The duration of the buffer can be adjusted using Slate.SleepBufferPostInput cvar (defaults to 1.0f)
- The FCurveSequence API has been updated to work with the active tick system
- Playing a curve sequence now requires that you pass the widget being animated by the sequence
- The active tick will automatically be registered on behalf of the widget and unregister when the sequence is complete
- GetLerpLooping() has been removed. Instead, pass true as the second param to Play() to indicate that the animation will loop. This causes the active tick to be registered indefinitely until paused or jumped to the start/end.
[CL 2391669 by Dan Hertzka in Main branch]
2014-12-17 16:07:57 -05:00
{
GraphPanel - > Update ( ) ;
2014-12-19 17:44:49 -05:00
bIsActiveTimerRegistered = false ;
return EActiveTimerReturnType : : Stop ;
---- Merging with SlateDev branch ----
Introduces the concept of "Active Ticking" to allow Slate to go to sleep when there is no need to update the UI.
While asleep, Slate will skip the Tick & Paint pass for that frame entirely.
- There are TWO ways to "wake" Slate and cause a Tick/Paint pass:
1. Provide some sort of input (mouse movement, clicks, and key presses). Slate will always tick when the user is active.
- Therefore, if the logic in a given widget's Tick is only relevant in response to user action, there is no need to register an active tick.
2. Register an Active Tick. Currently this is an all-or-nothing situation, so if a single active tick needs to execute, all of Slate will be ticked.
- The purpose of an Active Tick is to allow a widget to "drive" Slate and guarantee a Tick/Paint pass in the absence of any user action.
- Examples include animation, async operations that update periodically, progress updates, loading bars, etc.
- An empty active tick is registered for viewports when they are real-time, so game project widgets are unaffected by this change and should continue to work as before.
- An Active Tick is registered by creating an FWidgetActiveTickDelegate and passing it to SWidget::RegisterActiveTick()
- There are THREE ways to unregister an active tick:
1. Return EActiveTickReturnType::StopTicking from the active tick function
2. Pass the FActiveTickHandle returned by RegisterActiveTick() to SWidget::UnregisterActiveTick()
3. Destroy the widget responsible for the active tick
- Sleeping is currently disabled, can be enabled with Slate.AllowSlateToSleep cvar
- There is currently a little buffer time during which Slate continues to tick following any input. Long-term, this is planned to be removed.
- The duration of the buffer can be adjusted using Slate.SleepBufferPostInput cvar (defaults to 1.0f)
- The FCurveSequence API has been updated to work with the active tick system
- Playing a curve sequence now requires that you pass the widget being animated by the sequence
- The active tick will automatically be registered on behalf of the widget and unregister when the sequence is complete
- GetLerpLooping() has been removed. Instead, pass true as the second param to Play() to indicate that the animation will loop. This causes the active tick to be registered indefinitely until paused or jumped to the start/end.
[CL 2391669 by Dan Hertzka in Main branch]
2014-12-17 16:07:57 -05:00
}
2014-03-14 14:13:41 -04:00
void SGraphEditorImpl : : OnClosedActionMenu ( )
{
GraphPanel - > OnStopMakingConnection ( /*bForceStop=*/ true ) ;
}
2014-05-15 17:34:14 -04:00
FActionMenuContent SGraphEditorImpl : : GraphEd_OnGetContextMenuFor ( const FGraphContextMenuArguments & SpawnInfo )
2014-03-14 14:13:41 -04:00
{
if ( EdGraphObj ! = NULL )
{
const UEdGraphSchema * Schema = EdGraphObj - > GetSchema ( ) ;
check ( Schema ) ;
// Cache the pin this menu is being brought up for
2014-05-15 17:34:14 -04:00
GraphPinForMenu = SpawnInfo . GraphPin ;
2015-09-14 05:47:07 -04:00
GraphNodeForMenu = SpawnInfo . GraphNode ;
// Ensure we reset the GraphNodeForMenu when the menu closes
RegisterActiveTimer ( 0.1f , FWidgetActiveTimerDelegate : : CreateLambda ( [ this ] ( double , float ) {
if ( ! FSlateApplication : : Get ( ) . AnyMenusVisible ( ) )
{
GraphNodeForMenu = nullptr ;
return EActiveTimerReturnType : : Stop ;
}
return EActiveTimerReturnType : : Continue ;
} ) ) ;
2014-05-15 17:34:14 -04:00
if ( ( SpawnInfo . GraphPin ! = NULL ) | | ( SpawnInfo . GraphNode ! = NULL ) )
2014-03-14 14:13:41 -04:00
{
// Get all menu extenders for this context menu from the graph editor module
FGraphEditorModule & GraphEditorModule = FModuleManager : : GetModuleChecked < FGraphEditorModule > ( TEXT ( " GraphEditor " ) ) ;
TArray < FGraphEditorModule : : FGraphEditorMenuExtender_SelectedNode > MenuExtenderDelegates = GraphEditorModule . GetAllGraphEditorContextMenuExtender ( ) ;
TArray < TSharedPtr < FExtender > > Extenders ;
for ( int32 i = 0 ; i < MenuExtenderDelegates . Num ( ) ; + + i )
{
if ( MenuExtenderDelegates [ i ] . IsBound ( ) )
{
2014-05-15 17:34:14 -04:00
Extenders . Add ( MenuExtenderDelegates [ i ] . Execute ( this - > Commands . ToSharedRef ( ) , EdGraphObj , SpawnInfo . GraphNode , SpawnInfo . GraphPin , ! IsEditable . Get ( ) ) ) ;
2014-03-14 14:13:41 -04:00
}
}
TSharedPtr < FExtender > MenuExtender = FExtender : : Combine ( Extenders ) ;
// Show the menu for the pin or node under the cursor
const bool bShouldCloseAfterAction = true ;
FMenuBuilder MenuBuilder ( bShouldCloseAfterAction , this - > Commands , MenuExtender ) ;
2014-05-15 17:34:14 -04:00
Schema - > GetContextMenuActions ( EdGraphObj , SpawnInfo . GraphNode , SpawnInfo . GraphPin , & MenuBuilder , ! IsEditable . Get ( ) ) ;
2014-03-14 14:13:41 -04:00
return FActionMenuContent ( MenuBuilder . MakeWidget ( ) ) ;
}
else if ( IsEditable . Get ( ) )
{
if ( EdGraphObj - > GetSchema ( ) ! = NULL )
{
FActionMenuContent Content ;
if ( OnCreateActionMenu . IsBound ( ) )
{
Content = OnCreateActionMenu . Execute (
EdGraphObj ,
2014-05-15 17:34:14 -04:00
SpawnInfo . NodeAddPosition ,
SpawnInfo . DragFromPins ,
2014-03-14 14:13:41 -04:00
bAutoExpandActionMenu ,
SGraphEditor : : FActionMenuClosed : : CreateSP ( this , & SGraphEditorImpl : : OnClosedActionMenu )
) ;
}
else
{
TSharedRef < SGraphEditorActionMenu > Menu =
SNew ( SGraphEditorActionMenu )
. GraphObj ( EdGraphObj )
2014-05-15 17:34:14 -04:00
. NewNodePosition ( SpawnInfo . NodeAddPosition )
. DraggedFromPins ( SpawnInfo . DragFromPins )
2014-03-14 14:13:41 -04:00
. AutoExpandActionMenu ( bAutoExpandActionMenu )
. OnClosedCallback ( SGraphEditor : : FActionMenuClosed : : CreateSP ( this , & SGraphEditorImpl : : OnClosedActionMenu )
) ;
Content = FActionMenuContent ( Menu , Menu - > GetFilterTextBox ( ) ) ;
}
2014-05-15 17:34:14 -04:00
if ( SpawnInfo . DragFromPins . Num ( ) > 0 )
2014-03-14 14:13:41 -04:00
{
GraphPanel - > PreservePinPreviewUntilForced ( ) ;
}
return Content ;
}
2015-01-07 09:52:40 -05:00
return FActionMenuContent ( SNew ( STextBlock ) . Text ( NSLOCTEXT ( " GraphEditor " , " NoNodes " , " No Nodes " ) ) ) ;
2014-03-14 14:13:41 -04:00
}
else
{
2015-01-07 09:52:40 -05:00
return FActionMenuContent ( SNew ( STextBlock ) . Text ( NSLOCTEXT ( " GraphEditor " , " CannotCreateWhileDebugging " , " Cannot create new nodes in a read only graph " ) ) ) ;
2014-03-14 14:13:41 -04:00
}
}
else
{
2015-01-07 09:52:40 -05:00
return FActionMenuContent ( SNew ( STextBlock ) . Text ( NSLOCTEXT ( " GraphEditor " , " GraphObjectIsNull " , " Graph Object is Null " ) ) ) ;
2014-03-14 14:13:41 -04:00
}
}
bool SGraphEditorImpl : : CanReconstructNodes ( ) const
{
return IsGraphEditable ( ) & & ( GraphPanel - > SelectionManager . AreAnyNodesSelected ( ) ) ;
}
bool SGraphEditorImpl : : CanBreakNodeLinks ( ) const
{
return IsGraphEditable ( ) & & ( GraphPanel - > SelectionManager . AreAnyNodesSelected ( ) ) ;
}
bool SGraphEditorImpl : : CanBreakPinLinks ( ) const
{
return IsGraphEditable ( ) & & ( GraphPinForMenu ! = NULL ) ;
}
void SGraphEditorImpl : : ReconstructNodes ( )
{
const UEdGraphSchema * Schema = this - > EdGraphObj - > GetSchema ( ) ;
{
2014-04-23 19:52:00 -04:00
FScopedTransaction const Transaction ( LOCTEXT ( " ReconstructNodeTransaction " , " Refresh Node(s) " )) ;
for ( FGraphPanelSelectionSet : : TConstIterator NodeIt ( GraphPanel - > SelectionManager . GetSelectedNodes ( ) ) ; NodeIt ; + + NodeIt )
2014-03-14 14:13:41 -04:00
{
2014-04-23 19:52:00 -04:00
if ( UEdGraphNode * Node = Cast < UEdGraphNode > ( * NodeIt ) )
{
Schema - > ReconstructNode ( * Node ) ;
}
2014-03-14 14:13:41 -04:00
}
}
NotifyGraphChanged ( ) ;
}
void SGraphEditorImpl : : BreakNodeLinks ( )
{
const FScopedTransaction Transaction ( NSLOCTEXT ( " UnrealEd " , " GraphEd_BreakNodeLinks " , " Break Node Links " ) ) ;
for ( FGraphPanelSelectionSet : : TConstIterator NodeIt ( GraphPanel - > SelectionManager . GetSelectedNodes ( ) ) ; NodeIt ; + + NodeIt )
{
if ( UEdGraphNode * Node = Cast < UEdGraphNode > ( * NodeIt ) )
{
const UEdGraphSchema * Schema = Node - > GetSchema ( ) ;
Schema - > BreakNodeLinks ( * Node ) ;
}
}
}
void SGraphEditorImpl : : BreakPinLinks ( bool bSendNodeNotification )
{
const UEdGraphSchema * Schema = GraphPinForMenu - > GetSchema ( ) ;
Schema - > BreakPinLinks ( * GraphPinForMenu , bSendNodeNotification ) ;
}
FText SGraphEditorImpl : : GetZoomText ( ) const
{
return GraphPanel - > GetZoomText ( ) ;
}
FSlateColor SGraphEditorImpl : : GetZoomTextColorAndOpacity ( ) const
{
return GraphPanel - > GetZoomTextColorAndOpacity ( ) ;
}
bool SGraphEditorImpl : : IsGraphEditable ( ) const
{
2014-05-01 05:32:30 -04:00
return ( EdGraphObj ! = NULL ) & & IsEditable . Get ( ) ;
2014-03-14 14:13:41 -04:00
}
2015-05-07 12:39:59 -04:00
bool SGraphEditorImpl : : DisplayGraphAsReadOnly ( ) const
{
return ( EdGraphObj ! = NULL ) & & DisplayAsReadOnly . Get ( ) ;
}
2014-06-04 20:07:21 -04:00
bool SGraphEditorImpl : : IsLocked ( ) const
{
for ( auto LockedGraph : LockedGraphs )
{
if ( LockedGraph . IsValid ( ) )
{
return true ;
}
}
return false ;
}
2014-03-14 14:13:41 -04:00
TSharedPtr < SWidget > SGraphEditorImpl : : GetTitleBar ( ) const
{
return TitleBar ;
}
void SGraphEditorImpl : : SetViewLocation ( const FVector2D & Location , float ZoomAmount )
{
2014-06-04 20:07:21 -04:00
if ( GraphPanel . IsValid ( ) & & EdGraphObj & & ( ! IsLocked ( ) | | ! GraphPanel - > HasDeferredObjectFocus ( ) ) )
2014-03-14 14:13:41 -04:00
{
GraphPanel - > RestoreViewSettings ( Location , ZoomAmount ) ;
}
}
void SGraphEditorImpl : : GetViewLocation ( FVector2D & Location , float & ZoomAmount )
{
2014-06-04 20:07:21 -04:00
if ( GraphPanel . IsValid ( ) & & EdGraphObj & & ( ! IsLocked ( ) | | ! GraphPanel - > HasDeferredObjectFocus ( ) ) )
2014-03-14 14:13:41 -04:00
{
Location = GraphPanel - > GetViewOffset ( ) ;
ZoomAmount = GraphPanel - > GetZoomAmount ( ) ;
}
}
void SGraphEditorImpl : : LockToGraphEditor ( TWeakPtr < SGraphEditor > Other )
{
2014-06-04 20:07:21 -04:00
if ( ! LockedGraphs . Contains ( Other ) )
{
LockedGraphs . Push ( Other ) ;
}
2014-03-14 14:13:41 -04:00
if ( GraphPanel . IsValid ( ) )
{
FocusLockedEditorHere ( ) ;
}
}
2014-06-04 20:07:21 -04:00
void SGraphEditorImpl : : UnlockFromGraphEditor ( TWeakPtr < SGraphEditor > Other )
{
check ( Other . IsValid ( ) ) ;
int idx = LockedGraphs . Find ( Other ) ;
if ( ensureMsgf ( idx ! = INDEX_NONE , TEXT ( " Attempted to unlock graphs that were not locked together: %s %s " ) , * GetReadableLocation ( ) , * ( Other . Pin ( ) - > GetReadableLocation ( ) ) ) )
{
LockedGraphs . RemoveAtSwap ( idx ) ;
}
}
2014-03-14 14:13:41 -04:00
void SGraphEditorImpl : : AddNotification ( FNotificationInfo & Info , bool bSuccess )
{
// set up common notification properties
Info . bUseLargeFont = true ;
TSharedPtr < SNotificationItem > Notification = NotificationListPtr - > AddNotification ( Info ) ;
if ( Notification . IsValid ( ) )
{
Notification - > SetCompletionState ( bSuccess ? SNotificationItem : : CS_Success : SNotificationItem : : CS_Fail ) ;
}
}
void SGraphEditorImpl : : FocusLockedEditorHere ( )
{
2014-06-04 20:07:21 -04:00
for ( int i = 0 ; i < LockedGraphs . Num ( ) ; + + i )
2014-03-14 14:13:41 -04:00
{
2014-06-04 20:07:21 -04:00
TSharedPtr < SGraphEditor > LockedGraph = LockedGraphs [ i ] . Pin ( ) ;
if ( LockedGraph ! = TSharedPtr < SGraphEditor > ( ) )
{
LockedGraph - > SetViewLocation ( GraphPanel - > GetViewOffset ( ) , GraphPanel - > GetZoomAmount ( ) ) ;
}
else
{
LockedGraphs . RemoveAtSwap ( i - - ) ;
}
2014-03-14 14:13:41 -04:00
}
}
2016-05-10 16:00:39 -04:00
void SGraphEditorImpl : : SetPinVisibility ( SGraphEditor : : EPinVisibility InVisibility )
2014-03-14 14:13:41 -04:00
{
if ( GraphPanel . IsValid ( ) )
{
SGraphEditor : : EPinVisibility CachedVisibility = GraphPanel - > GetPinVisibility ( ) ;
2016-05-10 16:00:39 -04:00
GraphPanel - > SetPinVisibility ( InVisibility ) ;
if ( CachedVisibility ! = InVisibility )
2014-03-14 14:13:41 -04:00
{
NotifyGraphChanged ( ) ;
}
}
}
2014-05-01 05:32:30 -04:00
EVisibility SGraphEditorImpl : : ReadOnlyVisibility ( ) const
{
2014-06-09 11:12:17 -04:00
if ( ShowGraphStateOverlay . Get ( ) & & PIENotification ( ) = = EVisibility : : Hidden & & ! IsEditable . Get ( ) )
2014-05-01 05:32:30 -04:00
{
return EVisibility : : Visible ;
}
return EVisibility : : Hidden ;
}
2015-01-07 09:52:40 -05:00
FText SGraphEditorImpl : : GetInstructionText ( ) const
2014-09-12 18:42:03 -04:00
{
if ( Appearance . IsBound ( ) )
{
2015-01-07 09:52:40 -05:00
return Appearance . Get ( ) . InstructionText ;
2014-09-12 18:42:03 -04:00
}
2015-01-07 09:52:40 -05:00
return FText : : GetEmpty ( ) ;
2014-09-12 18:42:03 -04:00
}
2014-03-14 14:13:41 -04:00
2014-09-12 18:42:03 -04:00
EVisibility SGraphEditorImpl : : InstructionTextVisibility ( ) const
{
2014-09-16 15:11:30 -04:00
if ( ! GetInstructionText ( ) . IsEmpty ( ) & & ( GetInstructionTextFade ( ) > 0.0f ) )
2014-09-12 18:42:03 -04:00
{
Copying //UE4/Dev-Blueprints to Dev-Main (//UE4/Dev-Main) @ 2781164
#lockdown Nick.Penwarden
==========================
MAJOR FEATURES + CHANGES
==========================
Change 2716841 on 2015/10/05 by Mike.Beach
(WIP) Cleaning up how we setup script assets for replacement on cook (aligning more with the Blueprint conversion tool).
#codereview Maciej.Mroz
Change 2719089 on 2015/10/07 by Maciej.Mroz
ToValidCPPIdentifierChars handles propertly '?' char.
#codereview Dan.Oconnor
Change 2719361 on 2015/10/07 by Maciej.Mroz
Generated native code for AnimBPGC - some preliminary changes.
Refactor: UAnimBlueprintGeneratedClass is not accessed directly in runtime. It is accessed via UAnimClassInterface interface.
Properties USkeletalMeshComponent::AnimBlueprintGeneratedClass and UInterpTrackFloatAnimBPParam::AnimBlueprintClass were changed into "TSubclassOf<UAnimInstance> AnimClass"
The UDynamicClass also can deliver the IAnimClassInterface interface. See UAnimClassData, IAnimClassInterface::GetFromClass and UDynamicClass::AnimClassImplementation.
#codereview Lina.Halper, Thomas.Sarkanen
Change 2719383 on 2015/10/07 by Maciej.Mroz
Debug-only code removed
Change 2720528 on 2015/10/07 by Dan.Oconnor
Fix for determinsitc cooking of async tasks and load asset nodes
#codereview Mike.Beach, Maciej.Mroz
Change 2721273 on 2015/10/08 by Maciej.Mroz
Blueprint Compiler Cpp Backend
- Anim Blueprints can be converted
- Various fixes/improvements
Change 2721310 on 2015/10/08 by Maciej.Mroz
refactor (cl#2719361) - no "auto" keyword
Change 2721727 on 2015/10/08 by Mike.Beach
(WIP) Setup the cook commandlet so it handles converted assets, replacing them with generated classes.
- Refactored the conversion manifest (using a map over an array)
- Centralized destination paths into a helper struct (for the manifest)
- Generating an Editor module that automatically hooks into the cook process when enabled
- Loading and applying native replacments for the cook
Change 2723276 on 2015/10/09 by Michael.Schoell
Blueprints duplicated for PIE will no longer register as dependencies to other Blueprint.
#jira UE-16695 - Editor freezes then crashes while attempting to save during PIE
#jira UE-21614 - [CrashReport] Crash while saving during PIE - FKismetEditorUtilities::CompileBlueprint() kismet2.cpp:736
Change 2724345 on 2015/10/11 by Ben.Cosh
Blueprint profiler at first pass, this includes the ability to instrument specific blueprints with realtime editor stat display.
#UEBP-21 - Profiling data capture and storage
#UEBP-13 - Performance capture landing page
#Branch UE4
#Proj BlueprintProfiler, BlueprintGraph, EditorStyle, Kismet, UnrealEd, CoreUObject, Engine
Change 2724613 on 2015/10/12 by Ben.Cosh
Incremental update for blueprint profiler to fix the way some of the reported stats cascade through events and branches and additionally some missed bits of code are refactored/removed.
#Branch UE4
#Proj BlueprintProfiler
#info Whilst looking into this I spotted the reason why the stats seem so erratic, There appears to be an issue with FText's use of EXPERIMENTAL_TEXT_FAST_DECIMAL_FORMAT which I have reported, but ideally disable this locally until a fix is integrated.
Change 2724723 on 2015/10/12 by Maciej.Mroz
Constructor of a dynamic class creates CDO.
#codereview Robert.Manuszewski
Change 2725108 on 2015/10/12 by Mike.Beach
[UE-21891] Minor fix to the array shuffle() function; now processes the last entry like all the others.
Change 2726358 on 2015/10/13 by Maciej.Mroz
UDataTable is properly saved even if its RowStruct is null.
https://udn.unrealengine.com/questions/264064/crash-using-hotreload-in-custom-datatable-cdo-clas.html
Change 2727395 on 2015/10/13 by Mike.Beach
(WIP) Second pass on the Blueprint conversion pipeline; setting it up for more optimal (speedier) performance.
* Using stubs for replacements (rather than loading dynamic replacement).
* Giving the cook commandlet more control (so a conversion could be ran directly).
* Now logging replacements by old object path (to account for UPackage replacement queries).
* Fix for [UE-21947], unshelved from CL 2724944 (by Maciej.Mroz).
#codereview Maciej.Mroz
Change 2727484 on 2015/10/13 by Mike.Beach
[UE-22008] Fixing up comment/tooltip typo for UActorComponent::bAutoActivate.
Change 2727527 on 2015/10/13 by Mike.Beach
Downgrading an inactionable EdGraph warning, while adding more info so we could possibly determine what's happening.
Change 2727702 on 2015/10/13 by Dan.Oconnor
Fix for crash in UDelegateProperty::GetCPPType when called on a function with no OwnerClass (events)
Change 2727968 on 2015/10/14 by Maciej.Mroz
Since ConstructorHelpers::FClassFinder is usually static, the loaded class should be in root set, to prevent the pointer stored in ConstructorHelpers::FClassFinder from being obsolete.
FindOrLoadClass behaves now like FindOrLoadObject.
#codereview Robert.Manuszewski, Nick.Whiting
Change 2728139 on 2015/10/14 by Phillip.Kavan
2015-11-25 18:47:20 -05:00
return EVisibility : : HitTestInvisible ;
2014-09-12 18:42:03 -04:00
}
return EVisibility : : Hidden ;
}
float SGraphEditorImpl : : GetInstructionTextFade ( ) const
{
float InstructionOpacity = 1.0f ;
if ( Appearance . IsBound ( ) )
{
InstructionOpacity = Appearance . Get ( ) . InstructionFade . Get ( ) ;
}
return InstructionOpacity ;
}
FLinearColor SGraphEditorImpl : : InstructionTextTint ( ) const
{
return FLinearColor ( 1.f , 1.f , 1.f , GetInstructionTextFade ( ) ) ;
}
FSlateColor SGraphEditorImpl : : InstructionBorderColor ( ) const
{
FLinearColor BorderColor ( 0.1f , 0.1f , 0.1f , 0.7f ) ;
BorderColor . A * = GetInstructionTextFade ( ) ;
return BorderColor ;
}
2014-03-14 14:13:41 -04:00
Copying //UE4/Dev-Blueprints to Dev-Main (//UE4/Dev-Main)
==========================
MAJOR FEATURES + CHANGES
==========================
Change 2781504 on 2015/11/25 by Mike.Beach
Guarding against invalid nodes for deferred graph node actions (add, remove, select), by using TWeakObjectPtr instead of raw UEdGraphNode pointers.
#jira UE-23371
#codereview Dan.OConnor
Change 2781513 on 2015/11/25 by Michael.Schoell
Find-in-Blueprints optimized gathering.
Size of data has shrunk in the Asset Registry by up to one fifth the old size!
Performance moderately improved.
Load and save times of Blueprints increased, less redundant gathering of searchable data.
#jira UE-22928 - Optimize Find-in-Blueprints Gathering of Searchable Data
Change 2781517 on 2015/11/25 by Michael.Schoell
Marked FTimerHandle::Handle as a UPROPERTY(transient) so that Blueprints can check the equality of two instances of the structure.
#jira UE-23136 - Remove Item Node Removes All Objects in an Array
Change 2781804 on 2015/11/26 by Maciej.Mroz
Changed ConformImplementedEvents.
#jira UE-23738 BP_RiftMage_Ultimate fails to convert during cooking
#codereview Phillip.Kavan, Mike.Beach
Change 2781821 on 2015/11/26 by Ben.Cosh
This reinstates the blueprint debugging keymaps and adds additional functionality for step over and step out as key maps in the PIE world controls.
#UEBP-66 - Blueprint debug keymappings
#UE-16817 - Add step-in, step-over, and run until here functions for breakpoints
#UE-12481 - The F10 key doesn't work for stepping blueprint debugging
#Branch UE4
#Proj GraphEditor, Kismet, UnrealEd, CoreUObject, Slate
reviewedby chris.wood
Change 2781861 on 2015/11/26 by Maciej.Mroz
UE-23626 Converted tower defense game - you cannot click to place towers
CodeGenerator generates overriden exported names for events and functions.
#codereview Dan.Oconnor, Steve.Robb
Change 2782798 on 2015/11/30 by Maciej.Mroz
BP C++ conversion: components from SCS calls AttachTo (with ParentSocket parameter).
#jira UE-23862 Pawns in TowerDefenseGame don't move in converted build
#codereview Phillip.Kavan, Mike.Beach, Dan.Oconnor
Change 2782881 on 2015/11/30 by Michael.Schoell
Fixed ensure when promoting function graphs from interfaces during interface removal.
#jira UE-23717 - Ensure removing an implemented interface when transfering functions
Change 2783041 on 2015/11/30 by Maciej.Mroz
BP C++ conversion: All variables from Event Graph are listed as class properties.
#jira UE-23629 Converted tower defense game - Cam scrolls to upper left when mouse leaves window
#codereview Mike.Beach, Dan.Oconnor
Change 2783080 on 2015/11/30 by Michael.Schoell
Removing an interface function's output parameters will no longer cause Blueprints implementing the function to error.
Functions expected as event overrides will accept function graph implementations and give a warning informing that it is unexpected.
All function graphs (interfaces, interface implementations, overrides) can be duplicated. Parent function calls will be removed.
Duplicating graphs will correct names of objects in child Blueprints.
Function overrides of interfaces expected as an event can be deleted.
Duplicating graphs while in PIE is no longer possible.
When removing an interface, the operation can now be canceled.
#jira UE-13335 - Inside a BP Interface, changing a Function output to an input will cause a compile error in the reference bp
Change 2783338 on 2015/11/30 by Michael.Schoell
New output pins on function result nodes will properly fill out with valid default values.
All invalid pins will auto-validate themselves on node reconstruction when opening the Blueprint.
#jira UE-1928 - BLUEPRINTS: Default value not supplied for output parameters of function
Change 2783742 on 2015/11/30 by Phillip.Kavan
[UE-15463] Add special-case handling for failed imports of BPGC-owned component archetype objects on level load.
change summary:
- modified FLinkerLoad::VerifyImport() to customize the load error messaging for missing component archetype objects
Change 2784652 on 2015/12/01 by Ben.Cosh
Fix for crash whilst undoing the creation of a macro and currently displaying the tooltip in the blueprint editor.
#UE-23955 - Adding a macro graph through MyBlueprint and then calling undo causes a crash updating the macro tooltip.
#Branch UE4
#Proj Kismet
#CodeReview Chris.Wood
Change 2784834 on 2015/12/01 by Michael.Schoell
Added functions to convert from string to: Vector, Vector2D, Rotator, Color.
#jira UE-23761 - GitHub 1795 : [KismetStringLibrary] Convert String Back Into Vector, Rotator, Float, Adding Support for 2 way conversion! ? Rama
PR #1795
2015-12-16 17:17:43 -05:00
void SGraphEditorImpl : : CaptureKeyboard ( )
{
FSlateApplication : : Get ( ) . SetKeyboardFocus ( GraphPanel ) ;
}
2014-03-14 14:13:41 -04:00
/////////////////////////////////////////////////////
# undef LOCTEXT_NAMESPACE