2014-03-14 14:13:41 -04:00
// Copyright 1998-2014 Epic Games, Inc. All Rights Reserved.
# include "GraphEditorCommon.h"
# include "NodeFactory.h"
# include "Editor/UnrealEd/Public/DragAndDrop/ActorDragDropGraphEdOp.h"
# include "Editor/UnrealEd/Public/DragAndDrop/AssetDragDropOp.h"
# include "Editor/UnrealEd/Public/DragAndDrop/LevelDragDropOp.h"
# include "ConnectionDrawingPolicy.h"
# include "AssetSelection.h"
# include "ComponentAssetBroker.h"
# include "KismetNodes/KismetNodeInfoContext.h"
# include "GraphDiffControl.h"
2014-04-24 08:49:31 -04:00
# include "AnimationGraphSchema.h"
2014-04-24 14:34:01 -04:00
# include "AnimationStateMachineSchema.h"
2014-04-24 08:49:31 -04:00
2014-03-14 14:13:41 -04:00
DEFINE_LOG_CATEGORY_STATIC ( LogGraphPanel , Log , All ) ;
2014-04-25 05:03:13 -04:00
2014-04-26 09:55:34 -04:00
SGraphPanel : : FGraphPinHandle : : FGraphPinHandle ( UEdGraphPin * InPin )
2014-04-25 05:03:13 -04:00
{
2014-04-26 09:55:34 -04:00
if ( auto * Node = InPin - > GetOwningNode ( ) )
2014-04-25 05:03:13 -04:00
{
2014-04-26 09:55:34 -04:00
PinName = InPin - > PinName ;
NodeGuid = Node - > NodeGuid ;
}
}
TSharedPtr < SGraphPin > SGraphPanel : : FGraphPinHandle : : FindInGraphPanel ( const SGraphPanel & InPanel ) const
{
// First off, find the node
TSharedPtr < SGraphNode > GraphNode = InPanel . GetNodeWidgetFromGuid ( NodeGuid ) ;
if ( GraphNode . IsValid ( ) )
{
UEdGraphNode * Node = GraphNode - > GetNodeObj ( ) ;
UEdGraphPin * Pin = Node - > FindPin ( PinName ) ;
if ( Pin )
2014-04-25 05:03:13 -04:00
{
2014-04-26 09:55:34 -04:00
return GraphNode - > FindWidgetForPin ( Pin ) ;
2014-04-25 05:03:13 -04:00
}
}
2014-04-26 09:55:34 -04:00
return TSharedPtr < SGraphPin > ( ) ;
}
2014-04-25 05:03:13 -04:00
2014-03-14 14:13:41 -04:00
/**
* Construct a widget
*
* @ param InArgs The declaration describing how the widgets should be constructed .
*/
void SGraphPanel : : Construct ( const SGraphPanel : : FArguments & InArgs )
{
SNodePanel : : Construct ( ) ;
this - > OnGetContextMenuFor = InArgs . _OnGetContextMenuFor ;
this - > GraphObj = InArgs . _GraphObj ;
this - > GraphObjToDiff = InArgs . _GraphObjToDiff ;
this - > SelectionManager . OnSelectionChanged = InArgs . _OnSelectionChanged ;
this - > IsEditable = InArgs . _IsEditable ;
this - > OnNodeDoubleClicked = InArgs . _OnNodeDoubleClicked ;
this - > OnDropActor = InArgs . _OnDropActor ;
this - > OnDropStreamingLevel = InArgs . _OnDropStreamingLevel ;
this - > OnVerifyTextCommit = InArgs . _OnVerifyTextCommit ;
this - > OnTextCommitted = InArgs . _OnTextCommitted ;
this - > OnSpawnNodeByShortcut = InArgs . _OnSpawnNodeByShortcut ;
this - > OnUpdateGraphPanel = InArgs . _OnUpdateGraphPanel ;
this - > OnDisallowedPinConnection = InArgs . _OnDisallowedPinConnection ;
this - > bPreservePinPreviewConnection = false ;
this - > PinVisibility = SGraphEditor : : Pin_Show ;
CachedAllottedGeometryScaledSize = FVector2D ( 160 , 120 ) ;
if ( InArgs . _InitialZoomToFit )
{
ZoomToFit ( /*bOnlySelection=*/ false ) ;
bTeleportInsteadOfScrollingWhenZoomingToFit = true ;
}
BounceCurve . AddCurve ( 0.0f , 1.0f ) ;
BounceCurve . Play ( ) ;
// Register for notifications
MyRegisteredGraphChangedDelegate = FOnGraphChanged : : FDelegate : : CreateSP ( this , & SGraphPanel : : OnGraphChanged ) ;
this - > GraphObj - > AddOnGraphChangedHandler ( MyRegisteredGraphChangedDelegate ) ;
2014-06-09 11:12:17 -04:00
ShowGraphStateOverlay = InArgs . _ShowGraphStateOverlay ;
2014-03-14 14:13:41 -04:00
}
SGraphPanel : : ~ SGraphPanel ( )
{
this - > GraphObj - > RemoveOnGraphChangedHandler ( MyRegisteredGraphChangedDelegate ) ;
}
//////////////////////////////////////////////////////////////////////////
2014-07-23 08:23:21 -04:00
int32 SGraphPanel : : OnPaint ( const FPaintArgs & Args , const FGeometry & AllottedGeometry , const FSlateRect & MyClippingRect , FSlateWindowElementList & OutDrawElements , int32 LayerId , const FWidgetStyle & InWidgetStyle , bool bParentEnabled ) const
2014-03-14 14:13:41 -04:00
{
# if SLATE_HD_STATS
SCOPE_CYCLE_COUNTER ( STAT_SlateOnPaint_SGraphPanel ) ;
# endif
CachedAllottedGeometryScaledSize = AllottedGeometry . Size * AllottedGeometry . Scale ;
//Style used for objects that are the same between revisions
FWidgetStyle FadedStyle = InWidgetStyle ;
FadedStyle . BlendColorAndOpacityTint ( FLinearColor ( 0.45f , 0.45f , 0.45f , 0.45f ) ) ;
// First paint the background
const UEditorExperimentalSettings & Options = * GetDefault < UEditorExperimentalSettings > ( ) ;
const FSlateBrush * BackgroundImage = FEditorStyle : : GetBrush ( TEXT ( " Graph.Panel.SolidBackground " ) ) ;
PaintBackgroundAsLines ( BackgroundImage , AllottedGeometry , MyClippingRect , OutDrawElements , LayerId ) ;
const float ZoomFactor = AllottedGeometry . Scale * GetZoomAmount ( ) ;
FArrangedChildren ArrangedChildren ( EVisibility : : Visible ) ;
2014-07-22 04:03:40 -04:00
ArrangeChildNodes ( AllottedGeometry , ArrangedChildren ) ;
2014-03-14 14:13:41 -04:00
// Determine some 'global' settings based on current LOD
const bool bDrawScaledCommentBubblesThisFrame = GetCurrentLOD ( ) > EGraphRenderingLOD : : LowestDetail ;
const bool bDrawUnscaledCommentBubblesThisFrame = GetCurrentLOD ( ) < = EGraphRenderingLOD : : MediumDetail ;
const bool bDrawShadowsThisFrame = GetCurrentLOD ( ) > EGraphRenderingLOD : : LowestDetail ;
// Because we paint multiple children, we must track the maximum layer id that they produced in case one of our parents
// wants to an overlay for all of its contents.
// Save LayerId for comment boxes to ensure they always appear below nodes & wires
const int32 CommentNodeShadowLayerId = LayerId + + ;
const int32 CommentNodeLayerId = LayerId + + ;
// Save a LayerId for wires, which appear below nodes but above comments
// We will draw them later, along with the arrows which appear above nodes.
const int32 WireLayerId = LayerId + + ;
const int32 NodeShadowsLayerId = LayerId ;
const int32 NodeLayerId = NodeShadowsLayerId + 1 ;
int32 MaxLayerId = NodeLayerId ;
2014-09-15 21:48:46 -04:00
const FVector2D NodeShadowSize = GetDefault < UGraphEditorSettings > ( ) - > GetShadowDeltaSize ( ) ;
2014-03-14 14:13:41 -04:00
const UEdGraphSchema * Schema = GraphObj - > GetSchema ( ) ;
// Draw the child nodes
{
// When drawing a marquee, need a preview of what the selection will be.
const FGraphPanelSelectionSet * SelectionToVisualize = & ( SelectionManager . SelectedNodes ) ;
FGraphPanelSelectionSet SelectionPreview ;
if ( Marquee . IsValid ( ) )
{
ApplyMarqueeSelection ( Marquee , SelectionManager . SelectedNodes , SelectionPreview ) ;
SelectionToVisualize = & SelectionPreview ;
}
// Context for rendering node infos
FKismetNodeInfoContext Context ( GraphObj ) ;
TArray < FGraphDiffControl : : FNodeMatch > NodeMatches ;
for ( int32 ChildIndex = 0 ; ChildIndex < ArrangedChildren . Num ( ) ; + + ChildIndex )
{
2014-08-25 12:51:49 -04:00
FArrangedWidget & CurWidget = ArrangedChildren [ ChildIndex ] ;
2014-03-14 14:13:41 -04:00
TSharedRef < SGraphNode > ChildNode = StaticCastSharedRef < SGraphNode > ( CurWidget . Widget ) ;
// Examine node to see what layers we should be drawing in
int32 ShadowLayerId = NodeShadowsLayerId ;
int32 ChildLayerId = NodeLayerId ;
// If a comment node, draw in the dedicated comment slots
{
UObject * NodeObj = ChildNode - > GetObjectBeingDisplayed ( ) ;
if ( NodeObj & & NodeObj - > IsA ( UEdGraphNode_Comment : : StaticClass ( ) ) )
{
ShadowLayerId = CommentNodeShadowLayerId ;
ChildLayerId = CommentNodeLayerId ;
}
}
const bool bNodeIsVisible = FSlateRect : : DoRectanglesIntersect ( CurWidget . Geometry . GetClippingRect ( ) , MyClippingRect ) ;
if ( bNodeIsVisible )
{
const bool bSelected = SelectionToVisualize - > Contains ( StaticCastSharedRef < SNodePanel : : SNode > ( CurWidget . Widget ) - > GetObjectBeingDisplayed ( ) ) ;
// Handle Node renaming once the node is visible
if ( bSelected & & ChildNode - > IsRenamePending ( ) )
{
ChildNode - > ApplyRename ( ) ;
}
// Draw the node's shadow.
if ( bDrawShadowsThisFrame | | bSelected )
{
const FSlateBrush * ShadowBrush = ChildNode - > GetShadowBrush ( bSelected ) ;
FSlateDrawElement : : MakeBox (
OutDrawElements ,
ShadowLayerId ,
CurWidget . Geometry . ToInflatedPaintGeometry ( NodeShadowSize ) ,
ShadowBrush ,
MyClippingRect
) ;
}
// Draw the comments and information popups for this node, if it has any.
{
float CommentBubbleY = 0.0f ;
const FString NodeComment = ChildNode - > GetNodeComment ( ) ;
if ( ! NodeComment . IsEmpty ( ) )
{
// Comment bubbles have different LOD behavior:
// A comment box comment (bScaleComments=false) will only be shown when zoomed out (the title bar is readable instead when up close)
// A per-node comment (bScaleComments=true) will only be show when zoomed in (it gets too small to read)
const bool bScaleComments = ChildNode - > ShouldScaleNodeComment ( ) ;
const bool bShowCommentBubble = bScaleComments ? bDrawScaledCommentBubblesThisFrame : bDrawUnscaledCommentBubblesThisFrame ;
if ( bShowCommentBubble )
{
Change 2122846 on 2014/07/01 00:51:24 by Wes.Hunt@WHUNT-UE4-MAIN
#BUN UnrealMath updates
* added RotationAboutPointMatrix
* Added static Make() methods for the various derived FMatrix types. Allows single expressions that return an FMatrix so we don't have to rely on implicit conversion (which will break some generic programming).
* Simplified the implementation of FQuat::MakeFromEuler.
Change 2122848 on 2014/07/01 01:04:31 by Wes.Hunt@WHUNT-UE4-MAIN
Added SlateLayoutTransform to store a 2D translation and uniform scale (for FGeometry).
#BUN Added SlateTransformCalculus for handling arbitrary transform manipulation. See documentation in header.
Change 2123889 on 2014/07/01 17:12:40 by Wes.Hunt@WHUNT-UE4-MAIN
Remove unncessary use of FGeometry.
Change 2221407 on 2014/07/16 17:58:20 by Wes.Hunt@WHUNT-UE4-MAIN
TransformCalculus changes
* Move 2D versions of functions into SlateLayoutTransform header to separate it from the base 3D stuff.
* FSlateLayoutTransform is scale then translate now instead of translate then scale.
* TransformPosition -> TransformPoint
* Added a version of Concatenate taking 4 transforms.
* Update docs.
Change 2221408 on 2014/07/16 17:58:39 by Wes.Hunt@WHUNT-UE4-MAIN
Adjustments to Slate headers and PCH
Change 2221409 on 2014/07/16 17:59:07 by Wes.Hunt@WHUNT-UE4-MAIN
Transform calculus support for SlateRects
Change 2221459 on 2014/07/16 18:41:13 by Wes.Hunt@WHUNT-UE4-MAIN
#BUN SWindow changes
* Added GetLocalToScreenTransform. (Screen space == Desktop space)
** Basically contains the ApplicationScale and Window offset from the desktop.
* Added GetLocalToWindowTransform (Window space == Desktop space without the window offset)
* Added GetClientRectInScreen
** Allows code to know exactly WHERE the client rect is in the window.
* Refactored GetWindowGeometryInScreen and GetWindowGeometryInWindow to use the new methods above.
* SPopupLayer::OnArrangChildren refactored to clarify transformational spaces and use transformation calculus to do the work.
** This fixes PopupLayer to correctly account for the scale of the widget it is presenting a popup for.
** MenuAnchors that that create new SWindows still do no correctly account for scale.
Change 2221464 on 2014/07/16 18:45:25 by Wes.Hunt@WHUNT-UE4-MAIN
Render Transforms initial checkin. Lots of cleanup to do, but this is functionally working for all basic widgets and draw elements in slate. Main feature todos:
* restore pixel snapping.
* handle clipping in the presence of rotation.
Change 2226298 on 2014/07/21 21:22:46 by Wes.Hunt@WHUNT-UE4-MAIN
Use a better method to get the window's rectangle.
Change 2227809 on 2014/07/22 20:41:57 by Wes.Hunt@WHUNT-UE4-MAIN
Add 2D version of TransformVector to SlateTransform.
Change 2232085 on 2014/07/25 16:32:15 by Wes.Hunt@WHUNT-UE4-MAIN
Implement CPU pixel snapping even under render transform. This is pretty CPU intensive, but a reasonable POC.
Change 2232090 on 2014/07/25 16:33:10 by Wes.Hunt@WHUNT-UE4-MAIN
Font cache fixes for padding.
* Add 1 pixel of padding around all fonts.
* Fix font cache to properly handle padding
* Fix font cache to handle texture elements of zero size with non-zero padding.
Change 2232350 on 2014/07/25 19:50:11 by Wes.Hunt@WHUNT-UE4-MAIN
#BUN Updated FSlateTextureAtlas padding logic.
* Added ESlateTextureAtlasPaddingStyle which lets you choose from three atlasing padding styles:
* NoPadding - don't apply any padding (used to be Padding == 0).
* DilateBorder - copy border edges to apply 1-pixel padding (used to be Padding == 1).
* PadWithZero - expand 1-pixel border and fill it with zeros (new style).
* removed notion of Padding > 1 pixel from atlasing. It wasn't useful as we don't support mips or aniso filtering.
* Also the existing code didn't actually handle Padding > 1.
* FontCache now uses PadWithZero padding so upon zooming text, the edges get smoother.
Change 2237962 on 2014/07/31 02:17:28 by Wes.Hunt@WHUNT-UE4-MAIN
TransformCalculus tweak.
* Core Concatentate(T,T) no longer assumes the return type is T. Uses decltype(T.Concat(T)) instead.
Change 2237964 on 2014/07/31 02:21:31 by Wes.Hunt@WHUNT-UE4-MAIN
#BUN Added a full suite of transform types for 2D transformations that are transform calculus aware:
* FSlateScale2D
* FSlateShear2D
* FSlateQuat2D
* FSlateMatrix2x2
Added appropriate overloads and ConcatenateRules for all combinations, making them compatible with FSlateTransform and FSlateLayoutTransform.
FSlateTransform is now implemented in terms of a decomposed Matrix3x2.
Change 2237972 on 2014/07/31 02:30:45 by Wes.Hunt@WHUNT-UE4-MAIN
Remove 4x4 matrix from FSlateTransform
Change 2238004 on 2014/07/31 03:11:42 by Wes.Hunt@WHUNT-UE4-MAIN
FSlateTransform -> FSlateRenderTransform.
Change 2238714 on 2014/07/31 15:16:18 by Wes.Hunt@WHUNT-UE4-MAIN
#BUN Moved TransformCalculus into Core/Math.
* Split into TransformCalculus, 2D, and 3D support.
* FSlateRenderTransform is now just a typedef.
* Renamed 2D transform types to remove "Slate" from their name.
Change 2240437 on 2014/08/01 19:08:59 by Wes.Hunt@WHUNT-UE4-MAIN
Restore funky logic in deprecated FGeometry::MakeChild implementations.
* legacy FGeometry::MakeChild functions took OffsetFromParent in the local space of the widget. This therefore CANNOT be the layout transform offset, because that needs to be in parent space for the transform of P * S + T to work correctly.
* Therefore, the legacy functions now expect the ChildOffset to be in child space and re-apply the child scale to put them back into parent space.
* This fixes the NodePanels to properly handle zooming around the mouse cursor point.
Change 2242769 on 2014/08/04 13:44:33 by Wes.Hunt@WHUNT-UE4-MAIN
remove local layout transform storage from FGeometry.
Change 2242771 on 2014/08/04 13:45:59 by Wes.Hunt@WHUNT-UE4-MAIN
Update Declarative syntax support to call it RenderTransform instead of Transform.
Change 2245872 on 2014/08/06 14:45:44 by Wes.Hunt@WHUNT-UE4-MAIN
#BUN Add GetBottomRight function to FSlateRect.
Change 2246129 on 2014/08/06 17:32:04 by Wes.Hunt@WHUNT-UE4-MAIN
SThrobber now supports render transforms.
Key is to not use deprecated members of FPaintGeometry, which should be treated as immutable (at least public members shouldn't be modified withotu modifying the new members as well).
Change 2247782 on 2014/08/07 19:12:57 by Wes.Hunt@WHUNT-UE4-MAIN
Clipping widgets now works under render transforms, FPaintGeometry legacy fixes.
* Expanded FSlateVertex by 2 bytes to pass in local position.
* Change clipcoords to be passed in local space.
* Remove WorldPosition interpolator. Replaced by LocalPosition interpolator.
FPaintGeometry fixes
* FPaintGeometry now takes Size in LocalSpace unless using a legacy ctor. Avoid transform-and-back that was occurring when creating from an FGeometry, which already had it in local space, and rendering, which now wants it in local space.
* FPaintGeometry again supports mutability when using legacy members (like DrawPosition). This allows legacy code to mutate an FPaintGeometry, which is committed to a render transform right before rendering.Hacky, but allows legacy code that treated FPaintGeometry as a plain-old-struct to work.
* Removed a legacy ctor of FPaintGeoemtry that was not being used.
Misc:
* Turned off pixel snapping code in ElementBatcher because the FSlateVertex is doing it during construction.
* Still texture filtering artifacts to figure out, so the last word has not been spoken on this yet!
* Tweaked FGeometry::MakeRoot to use the non-render transform ctor since it doesn't need to use it.
* Removed /*WindowSpace*/ Size member from SlateDrawElement.
* SlateDrawElement::GetRotationPoint vastly simplified by using Local space.
* Moved slate cycle counters back to the top of the function in ElementBatcher.
* Uninlined FSlateVertex ctors so I can tweak their rounding rules without a full recompile.
Change 2247790 on 2014/08/07 19:20:01 by Wes.Hunt@WHUNT-UE4-MAIN
SSlider no longer uses MakeRotatedBox, correctly handles render transforms.
* Now uses a render transform to draw a vertical slider handle instead of MakeRotatedBox.
* Since we don't support layout transforms, we also have to adjust the clip rect to account for the render-only transform, and make it act like a layout transform.
Change 2249106 on 2014/08/08 19:13:21 by Wes.Hunt@WHUNT-UE4-MAIN
Slate clipping now done in window space again.
* This addresses subpixel jittering that occured on otherwise stable clip rects because local space was moving underneath, and transforming the clip rect to local space created occasional rounding errors.
* Implemented a vectorized point-in-parallelogram check in the pixel shaders to do this. Now pass clip rect in slightly differently, and moved to a float16 to allow better clip precision under rotation. But the vertex data remains the same size.
* Moved some more common transform work into FSlateVertex constructor to save duplication.
* Removed construction of local clip rect as it's no longer needed except for text rendering.
* Hoisted construction of local clip rect out of the text drawing character loop (whoops).
* Precompute InverseLayoutTransform in draw code as we use that a lot now.
* Fixed OGL renderer to work.
Change 2249123 on 2014/08/08 19:45:19 by Wes.Hunt@WHUNT-UE4-MAIN
SProgressBar no longer uses a temporary PaintGeometry to create the inner clipping rect for drawing, it directly inflates the clipping rect now. Also tried to adjust the coords to reduce jitter in the one-pixel padding.
Change 2251914 on 2014/08/11 16:26:12 by Wes.Hunt@WHUNT-UE4-MAIN
Fixing HitTest 2.0 to work with latest code.
* Added AppendTransform to FGeometry to preserve immutability of the struct.
Change 2253023 on 2014/08/12 10:30:23 by Wes.Hunt@WHUNT-UE4-MAIN
Fixing Slate RHI Renderer to use new screenspace clipping with render transforms.
Change 2253090 on 2014/08/12 11:36:16 by Wes.Hunt@WHUNT-UE4-MAIN
Fix SClippingHorizontalBox to use immutable FGeometry position. Also fix to properly support scale in when it needs to clip children.
Change 2253701 on 2014/08/12 17:48:06 by Wes.Hunt@WHUNT-UE4-MAIN
#BUN Round viewport rect instead of trunc to match how slate does it now (fixes 1:1 pixel error on SViewports). Need to abstract slate rounding internals so clients don't have to guess.
Change 2255403 on 2014/08/13 19:08:25 by Wes.Hunt@WHUNT-UE4-MAIN
#BUN Added LayoutGeometry class.
Change 2255404 on 2014/08/13 19:10:40 by Wes.Hunt@WHUNT-UE4-MAIN
#BUN Made FGeometry public members const to catch all mutating uses of them. Added some hacks in the implementation to make it backward compatible.
Removed the AccumulatedLayoutTransform, since it was just a copy of AbsolutePosition and Scale. Now all code creates the layout transform on the fly from those members. Still functionally the same.
Added support for MakeChild using FLayoutGeometry.
Change 2255405 on 2014/08/13 19:12:39 by Wes.Hunt@WHUNT-UE4-MAIN
Changed SSplitter and Splitter2x2 to use FLayoutTransforms where possible. Now only calls ArrangeChildren() when rendering, avoiding accumulating the layout transforms and storing the render transforms altogether.
Change 2265162 on 2014/08/20 18:24:04 by Wes.Hunt@WHUNT-UE4-MAIN
Implement MakeRotatedBox in terms of a render transform. Remove all shader code associated with rotating.
Change 2268034 on 2014/08/22 17:40:05 by Wes.Hunt@WHUNT-UE4-MAIN
More 2D transform cleanup.
* Removed a bunch of todo comments from the code, and converted them to more of a final form for main.
* #BUN Removed FGeometry::CenteredPaintGeometryBelow as it was misleading, and users of the function were forced to mutate the resulting FPaintGeometry.
* #BUN Removed FGeometry::GetRect() because it returned a rect in a weird space if the local scale != 1. Only one place in the code actually used it.
Change 2268096 on 2014/08/22 18:12:41 by Wes.Hunt@WHUNT-UE4-MAIN
Clean up more stuff in FPaintGeometry.
* #BUN Removed ToSlateRect and Identity().
* Removed storage of accumulated layout transform, since DrawPosition and DrawScale implicitly stored it.
* Removed a bunch of todo comments and converted them to a more final form.
Change 2270989 on 2014/08/25 15:48:46 by Wes.Hunt@WHUNT-UE4-MAIN
Add support for Concatenate with 5 transforms.
Change 2271394 on 2014/08/25 19:12:53 by Wes.Hunt@WHUNT-UE4-MAIN
#BUN Added an OffsetBy function to FSlateRect
Change 2271395 on 2014/08/25 19:13:56 by Wes.Hunt@WHUNT-UE4-MAIN
Added a version of FSlateRotatedRect that uses regular floats, also added IsUnderLocation ToBoundingRect function for overlap testing.
Change 2271396 on 2014/08/25 19:14:38 by Wes.Hunt@WHUNT-UE4-MAIN
HitTest 2.0 now works with render transforms.
#codereview:matt.kuhlenschmidt,nick.atamas
[CL 2276499 by Wes Hunt in Main branch]
2014-08-28 14:29:46 -04:00
FGeometry CommentGeometry = CurWidget . Geometry . MakeChild ( CurWidget . Geometry . Size , FSlateLayoutTransform ( bScaleComments ? 1.0f : Inverse ( CurWidget . Geometry . Scale ) ) ) ;
2014-03-14 14:13:41 -04:00
PaintComment ( NodeComment , CommentGeometry , MyClippingRect , OutDrawElements , ChildLayerId , ChildNode - > GetNodeCommentColor ( ) . GetColor ( InWidgetStyle ) , /*inout*/ CommentBubbleY , InWidgetStyle ) ;
}
}
Context . bSelected = bSelected ;
TArray < FGraphInformationPopupInfo > Popups ;
{
ChildNode - > GetNodeInfoPopups ( & Context , /*out*/ Popups ) ;
}
for ( int32 PopupIndex = 0 ; PopupIndex < Popups . Num ( ) ; + + PopupIndex )
{
FGraphInformationPopupInfo & Popup = Popups [ PopupIndex ] ;
PaintComment ( Popup . Message , CurWidget . Geometry , MyClippingRect , OutDrawElements , ChildLayerId , Popup . BackgroundColor , /*inout*/ CommentBubbleY , InWidgetStyle ) ;
}
}
int32 CurWidgetsMaxLayerId ;
{
UEdGraphNode * NodeObj = Cast < UEdGraphNode > ( ChildNode - > GetObjectBeingDisplayed ( ) ) ;
/** When diffing nodes, nodes that are different between revisions are opaque, nodes that have not changed are faded */
FGraphDiffControl : : FNodeMatch NodeMatch = FGraphDiffControl : : FindNodeMatch ( GraphObjToDiff , NodeObj , NodeMatches ) ;
if ( NodeMatch . IsValid ( ) )
{
NodeMatches . Add ( NodeMatch ) ;
}
const bool bNodeIsDifferent = ( ! GraphObjToDiff | | NodeMatch . Diff ( ) ) ;
/* When dragging off a pin, we want to duck the alpha of some nodes */
2014-04-25 05:03:13 -04:00
TSharedPtr < SGraphPin > OnlyStartPin = ( 1 = = PreviewConnectorFromPins . Num ( ) ) ? PreviewConnectorFromPins [ 0 ] . FindInGraphPanel ( * this ) : TSharedPtr < SGraphPin > ( ) ;
2014-03-14 14:13:41 -04:00
const bool bNodeIsNotUsableInCurrentContext = Schema - > FadeNodeWhenDraggingOffPin ( NodeObj , OnlyStartPin . IsValid ( ) ? OnlyStartPin . Get ( ) - > GetPinObj ( ) : NULL ) ;
const FWidgetStyle & NodeStyleToUse = ( bNodeIsDifferent & & ! bNodeIsNotUsableInCurrentContext ) ? InWidgetStyle : FadedStyle ;
// Draw the node.O
2014-07-23 08:23:21 -04:00
CurWidgetsMaxLayerId = CurWidget . Widget - > Paint ( Args . WithNewParent ( this ) , CurWidget . Geometry , MyClippingRect , OutDrawElements , ChildLayerId , NodeStyleToUse , ShouldBeEnabled ( bParentEnabled ) ) ;
2014-03-14 14:13:41 -04:00
}
// Draw the node's overlay, if it has one.
{
// Get its size
const FVector2D WidgetSize = CurWidget . Geometry . Size ;
{
2014-07-22 04:03:40 -04:00
TArray < FOverlayBrushInfo > OverlayBrushes ;
ChildNode - > GetOverlayBrushes ( bSelected , WidgetSize , /*out*/ OverlayBrushes ) ;
for ( int32 BrushIndex = 0 ; BrushIndex < OverlayBrushes . Num ( ) ; + + BrushIndex )
2014-03-14 14:13:41 -04:00
{
2014-07-22 04:03:40 -04:00
FOverlayBrushInfo & OverlayInfo = OverlayBrushes [ BrushIndex ] ;
const FSlateBrush * OverlayBrush = OverlayInfo . Brush ;
if ( OverlayBrush ! = NULL )
{
FPaintGeometry BouncedGeometry = CurWidget . Geometry . ToPaintGeometry ( OverlayInfo . OverlayOffset , OverlayBrush - > ImageSize , 1.f ) ;
2014-03-14 14:13:41 -04:00
2014-07-22 04:03:40 -04:00
// Handle bouncing
const float BounceValue = FMath : : Sin ( 2.0f * PI * BounceCurve . GetLerpLooping ( ) ) ;
BouncedGeometry . DrawPosition + = ( OverlayInfo . AnimationEnvelope * BounceValue * ZoomFactor ) ;
CurWidgetsMaxLayerId + + ;
FSlateDrawElement : : MakeBox (
OutDrawElements ,
CurWidgetsMaxLayerId ,
BouncedGeometry ,
OverlayBrush ,
MyClippingRect
) ;
}
2014-03-14 14:13:41 -04:00
}
2014-07-22 04:03:40 -04:00
}
2014-03-14 14:13:41 -04:00
2014-07-22 04:03:40 -04:00
{
TArray < FOverlayWidgetInfo > OverlayWidgets = ChildNode - > GetOverlayWidgets ( bSelected , WidgetSize ) ;
for ( int32 WidgetIndex = 0 ; WidgetIndex < OverlayWidgets . Num ( ) ; + + WidgetIndex )
{
FOverlayWidgetInfo & OverlayInfo = OverlayWidgets [ WidgetIndex ] ;
if ( OverlayInfo . Widget - > GetVisibility ( ) = = EVisibility : : Visible )
{
// call SlatePrepass as these widgets are not in the 'normal' child hierarchy
OverlayInfo . Widget - > SlatePrepass ( ) ;
const FGeometry WidgetGeometry = CurWidget . Geometry . MakeChild ( OverlayInfo . OverlayOffset , OverlayInfo . Widget - > GetDesiredSize ( ) , 1.f ) ;
2014-07-23 08:23:21 -04:00
OverlayInfo . Widget - > Paint ( Args . WithNewParent ( this ) , WidgetGeometry , MyClippingRect , OutDrawElements , CurWidgetsMaxLayerId , InWidgetStyle , bParentEnabled ) ;
2014-07-22 04:03:40 -04:00
}
}
2014-03-14 14:13:41 -04:00
}
}
MaxLayerId = FMath : : Max ( MaxLayerId , CurWidgetsMaxLayerId + 1 ) ;
}
}
}
MaxLayerId + = 1 ;
// Draw connections between pins
if ( Children . Num ( ) > 0 )
{
//@TODO: Pull this into a factory like the pin and node ones
FConnectionDrawingPolicy * ConnectionDrawingPolicy ;
{
ConnectionDrawingPolicy = Schema - > CreateConnectionDrawingPolicy ( WireLayerId , MaxLayerId , ZoomFactor , MyClippingRect , OutDrawElements , GraphObj ) ;
if ( ! ConnectionDrawingPolicy )
{
if ( Schema - > IsA ( UAnimationGraphSchema : : StaticClass ( ) ) )
{
ConnectionDrawingPolicy = new FAnimGraphConnectionDrawingPolicy ( WireLayerId , MaxLayerId , ZoomFactor , MyClippingRect , OutDrawElements , GraphObj ) ;
}
else if ( Schema - > IsA ( UAnimationStateMachineSchema : : StaticClass ( ) ) )
{
ConnectionDrawingPolicy = new FStateMachineConnectionDrawingPolicy ( WireLayerId , MaxLayerId , ZoomFactor , MyClippingRect , OutDrawElements , GraphObj ) ;
}
else if ( Schema - > IsA ( UEdGraphSchema_K2 : : StaticClass ( ) ) )
{
ConnectionDrawingPolicy = new FKismetConnectionDrawingPolicy ( WireLayerId , MaxLayerId , ZoomFactor , MyClippingRect , OutDrawElements , GraphObj ) ;
}
else if ( Schema - > IsA ( USoundCueGraphSchema : : StaticClass ( ) ) )
{
ConnectionDrawingPolicy = new FSoundCueGraphConnectionDrawingPolicy ( WireLayerId , MaxLayerId , ZoomFactor , MyClippingRect , OutDrawElements , GraphObj ) ;
}
else if ( Schema - > IsA ( UMaterialGraphSchema : : StaticClass ( ) ) )
{
ConnectionDrawingPolicy = new FMaterialGraphConnectionDrawingPolicy ( WireLayerId , MaxLayerId , ZoomFactor , MyClippingRect , OutDrawElements , GraphObj ) ;
}
else
{
ConnectionDrawingPolicy = new FConnectionDrawingPolicy ( WireLayerId , MaxLayerId , ZoomFactor , MyClippingRect , OutDrawElements ) ;
}
}
}
2014-04-25 05:03:13 -04:00
TArray < TSharedPtr < SGraphPin > > OverridePins ;
for ( const FGraphPinHandle & Handle : PreviewConnectorFromPins )
{
TSharedPtr < SGraphPin > Pin = Handle . FindInGraphPanel ( * this ) ;
if ( Pin . IsValid ( ) )
{
OverridePins . Add ( Pin ) ;
}
}
ConnectionDrawingPolicy - > SetHoveredPins ( CurrentHoveredPins , OverridePins , TimeSinceMouseEnteredPin ) ;
2014-03-14 14:13:41 -04:00
ConnectionDrawingPolicy - > SetMarkedPin ( MarkedPin ) ;
// Get the set of pins for all children and synthesize geometry for culled out pins so lines can be drawn to them.
TMap < TSharedRef < SWidget > , FArrangedWidget > PinGeometries ;
TSet < TSharedRef < SWidget > > VisiblePins ;
for ( int32 ChildIndex = 0 ; ChildIndex < Children . Num ( ) ; + + ChildIndex )
{
TSharedRef < SGraphNode > ChildNode = StaticCastSharedRef < SGraphNode > ( Children [ ChildIndex ] ) ;
// If this is a culled node, approximate the pin geometry to the corner of the node it is within
if ( IsNodeCulled ( ChildNode , AllottedGeometry ) )
{
TArray < TSharedRef < SWidget > > NodePins ;
ChildNode - > GetPins ( NodePins ) ;
const FVector2D NodeLoc = ChildNode - > GetPosition ( ) ;
const FGeometry SynthesizedNodeGeometry ( GraphCoordToPanelCoord ( NodeLoc ) , AllottedGeometry . AbsolutePosition , FVector2D : : ZeroVector , 1.f ) ;
for ( TArray < TSharedRef < SWidget > > : : TConstIterator NodePinIterator ( NodePins ) ; NodePinIterator ; + + NodePinIterator )
{
const SGraphPin & PinWidget = static_cast < const SGraphPin & > ( ( * NodePinIterator ) . Get ( ) ) ;
FVector2D PinLoc = NodeLoc + PinWidget . GetNodeOffset ( ) ;
const FGeometry SynthesizedPinGeometry ( GraphCoordToPanelCoord ( PinLoc ) , AllottedGeometry . AbsolutePosition , FVector2D : : ZeroVector , 1.f ) ;
PinGeometries . Add ( * NodePinIterator , FArrangedWidget ( * NodePinIterator , SynthesizedPinGeometry ) ) ;
}
// Also add synthesized geometries for culled nodes
ArrangedChildren . AddWidget ( FArrangedWidget ( ChildNode , SynthesizedNodeGeometry ) ) ;
}
else
{
ChildNode - > GetPins ( VisiblePins ) ;
}
}
// Now get the pin geometry for all visible children and append it to the PinGeometries map
TMap < TSharedRef < SWidget > , FArrangedWidget > VisiblePinGeometries ;
{
this - > FindChildGeometries ( AllottedGeometry , VisiblePins , VisiblePinGeometries ) ;
PinGeometries . Append ( VisiblePinGeometries ) ;
}
// Draw preview connections (only connected on one end)
if ( PreviewConnectorFromPins . Num ( ) > 0 )
{
2014-04-25 05:03:13 -04:00
for ( const FGraphPinHandle & Handle : PreviewConnectorFromPins )
2014-03-14 14:13:41 -04:00
{
2014-04-25 05:03:13 -04:00
TSharedPtr < SGraphPin > CurrentStartPin = Handle . FindInGraphPanel ( * this ) ;
if ( ! CurrentStartPin . IsValid ( ) )
{
continue ;
}
2014-03-14 14:13:41 -04:00
const FArrangedWidget * PinGeometry = PinGeometries . Find ( CurrentStartPin . ToSharedRef ( ) ) ;
if ( PinGeometry ! = NULL )
{
FVector2D StartPoint ;
FVector2D EndPoint ;
if ( CurrentStartPin - > GetDirection ( ) = = EGPD_Input )
{
StartPoint = AllottedGeometry . AbsolutePosition + PreviewConnectorEndpoint ;
EndPoint = FGeometryHelper : : VerticalMiddleLeftOf ( PinGeometry - > Geometry ) - FVector2D ( ConnectionDrawingPolicy - > ArrowRadius . X , 0 ) ;
}
else
{
StartPoint = FGeometryHelper : : VerticalMiddleRightOf ( PinGeometry - > Geometry ) ;
EndPoint = AllottedGeometry . AbsolutePosition + PreviewConnectorEndpoint ;
}
ConnectionDrawingPolicy - > DrawPreviewConnector ( PinGeometry - > Geometry , StartPoint , EndPoint , CurrentStartPin . Get ( ) - > GetPinObj ( ) ) ;
}
//@TODO: Re-evaluate this incompatible mojo; it's mutating every pin state every frame to accomplish a visual effect
ConnectionDrawingPolicy - > SetIncompatiblePinDrawState ( CurrentStartPin , VisiblePins ) ;
}
}
else
{
//@TODO: Re-evaluate this incompatible mojo; it's mutating every pin state every frame to accomplish a visual effect
ConnectionDrawingPolicy - > ResetIncompatiblePinDrawState ( VisiblePins ) ;
}
// Draw all regular connections
ConnectionDrawingPolicy - > Draw ( PinGeometries , ArrangedChildren ) ;
delete ConnectionDrawingPolicy ;
}
// Draw a shadow overlay around the edges of the graph
+ + MaxLayerId ;
PaintSurroundSunkenShadow ( FEditorStyle : : GetBrush ( TEXT ( " Graph.Shadow " ) ) , AllottedGeometry , MyClippingRect , OutDrawElements , MaxLayerId ) ;
2014-06-09 11:12:17 -04:00
if ( ShowGraphStateOverlay . Get ( ) )
2014-03-14 14:13:41 -04:00
{
2014-06-09 11:12:17 -04:00
const FSlateBrush * BorderBrush = nullptr ;
if ( ( GEditor - > bIsSimulatingInEditor | | GEditor - > PlayWorld ! = NULL ) )
{
// Draw a surrounding indicator when PIE is active, to make it clear that the graph is read-only, etc...
BorderBrush = FEditorStyle : : GetBrush ( TEXT ( " Graph.PlayInEditor " ) ) ;
}
else if ( ! IsEditable . Get ( ) )
{
// Draw a different border when we're not simulating but the graph is read-only
BorderBrush = FEditorStyle : : GetBrush ( TEXT ( " Graph.ReadOnlyBorder " ) ) ;
}
2014-05-01 05:32:30 -04:00
2014-06-09 11:12:17 -04:00
if ( BorderBrush )
{
// Actually draw the border
FSlateDrawElement : : MakeBox (
OutDrawElements ,
MaxLayerId ,
AllottedGeometry . ToPaintGeometry ( ) ,
BorderBrush ,
MyClippingRect
) ;
}
2014-03-14 14:13:41 -04:00
}
// Draw the marquee selection rectangle
PaintMarquee ( AllottedGeometry , MyClippingRect , OutDrawElements , MaxLayerId ) ;
// Draw the software cursor
+ + MaxLayerId ;
PaintSoftwareCursor ( AllottedGeometry , MyClippingRect , OutDrawElements , MaxLayerId ) ;
return MaxLayerId ;
}
bool SGraphPanel : : SupportsKeyboardFocus ( ) const
{
return true ;
}
2014-07-22 04:03:40 -04:00
void SGraphPanel : : OnArrangeChildren ( const FGeometry & AllottedGeometry , FArrangedChildren & ArrangedChildren ) const
{
SNodePanel : : OnArrangeChildren ( AllottedGeometry , ArrangedChildren ) ;
FArrangedChildren MyArrangedChildren ( ArrangedChildren . GetFilter ( ) ) ;
for ( int32 ChildIndex = 0 ; ChildIndex < ArrangedChildren . Num ( ) ; + + ChildIndex )
{
2014-08-25 12:51:49 -04:00
FArrangedWidget & CurWidget = ArrangedChildren [ ChildIndex ] ;
2014-07-22 04:03:40 -04:00
TSharedRef < SGraphNode > ChildNode = StaticCastSharedRef < SGraphNode > ( CurWidget . Widget ) ;
TArray < FOverlayWidgetInfo > OverlayWidgets = ChildNode - > GetOverlayWidgets ( false , CurWidget . Geometry . Size ) ;
for ( int32 WidgetIndex = 0 ; WidgetIndex < OverlayWidgets . Num ( ) ; + + WidgetIndex )
{
FOverlayWidgetInfo & OverlayInfo = OverlayWidgets [ WidgetIndex ] ;
MyArrangedChildren . AddWidget ( AllottedGeometry . MakeChild ( OverlayInfo . Widget . ToSharedRef ( ) , CurWidget . Geometry . Position + OverlayInfo . OverlayOffset , OverlayInfo . Widget - > GetDesiredSize ( ) , GetZoomAmount ( ) ) ) ;
}
}
ArrangedChildren . Append ( MyArrangedChildren ) ;
}
2014-03-14 14:13:41 -04:00
void SGraphPanel : : UpdateSelectedNodesPositions ( FVector2D PositionIncrement )
{
for ( FGraphPanelSelectionSet : : TIterator NodeIt ( SelectionManager . SelectedNodes ) ; NodeIt ; + + NodeIt )
{
TSharedRef < SNode > * pWidget = NodeToWidgetLookup . Find ( * NodeIt ) ;
if ( pWidget ! = NULL )
{
SNode & Widget = pWidget - > Get ( ) ;
2014-05-06 04:45:44 -04:00
SNode : : FNodeSet NodeFilter ;
Widget . MoveTo ( Widget . GetPosition ( ) + PositionIncrement , NodeFilter ) ;
2014-03-14 14:13:41 -04:00
}
}
}
FReply SGraphPanel : : OnKeyDown ( const FGeometry & MyGeometry , const FKeyboardEvent & InKeyboardEvent )
{
if ( IsEditable . Get ( ) )
{
if ( InKeyboardEvent . GetKey ( ) = = EKeys : : Up | | InKeyboardEvent . GetKey ( ) = = EKeys : : NumPadEight )
{
UpdateSelectedNodesPositions ( FVector2D ( 0.0f , - GetSnapGridSize ( ) ) ) ;
return FReply : : Handled ( ) ;
}
if ( InKeyboardEvent . GetKey ( ) = = EKeys : : Down | | InKeyboardEvent . GetKey ( ) = = EKeys : : NumPadTwo )
{
UpdateSelectedNodesPositions ( FVector2D ( 0.0f , GetSnapGridSize ( ) ) ) ;
return FReply : : Handled ( ) ;
}
if ( InKeyboardEvent . GetKey ( ) = = EKeys : : Right | | InKeyboardEvent . GetKey ( ) = = EKeys : : NumPadSix )
{
UpdateSelectedNodesPositions ( FVector2D ( GetSnapGridSize ( ) , 0.0f ) ) ;
return FReply : : Handled ( ) ;
}
if ( InKeyboardEvent . GetKey ( ) = = EKeys : : Left | | InKeyboardEvent . GetKey ( ) = = EKeys : : NumPadFour )
{
UpdateSelectedNodesPositions ( FVector2D ( - GetSnapGridSize ( ) , 0.0f ) ) ;
return FReply : : Handled ( ) ;
}
if ( InKeyboardEvent . GetKey ( ) = = EKeys : : Subtract )
{
ChangeZoomLevel ( - 1 , CachedAllottedGeometryScaledSize / 2.f , InKeyboardEvent . IsControlDown ( ) ) ;
return FReply : : Handled ( ) ;
}
if ( InKeyboardEvent . GetKey ( ) = = EKeys : : Add )
{
ChangeZoomLevel ( + 1 , CachedAllottedGeometryScaledSize / 2.f , InKeyboardEvent . IsControlDown ( ) ) ;
return FReply : : Handled ( ) ;
}
}
return SNodePanel : : OnKeyDown ( MyGeometry , InKeyboardEvent ) ;
}
void SGraphPanel : : GetAllPins ( TSet < TSharedRef < SWidget > > & AllPins )
{
// Get the set of pins for all children
for ( int32 ChildIndex = 0 ; ChildIndex < Children . Num ( ) ; + + ChildIndex )
{
TSharedRef < SGraphNode > ChildNode = StaticCastSharedRef < SGraphNode > ( Children [ ChildIndex ] ) ;
ChildNode - > GetPins ( AllPins ) ;
}
}
void SGraphPanel : : AddPinToHoverSet ( UEdGraphPin * HoveredPin )
{
CurrentHoveredPins . Add ( HoveredPin ) ;
TimeSinceMouseEnteredPin = FSlateApplication : : Get ( ) . GetCurrentTime ( ) ;
}
void SGraphPanel : : RemovePinFromHoverSet ( UEdGraphPin * UnhoveredPin )
{
CurrentHoveredPins . Remove ( UnhoveredPin ) ;
TimeSinceMouseLeftPin = FSlateApplication : : Get ( ) . GetCurrentTime ( ) ;
}
void SGraphPanel : : ArrangeChildrenForContextMenuSummon ( const FGeometry & AllottedGeometry , FArrangedChildren & ArrangedChildren ) const
{
// First pass nodes
for ( int32 ChildIndex = 0 ; ChildIndex < VisibleChildren . Num ( ) ; + + ChildIndex )
{
const TSharedRef < SNode > & SomeChild = VisibleChildren [ ChildIndex ] ;
if ( ! SomeChild - > RequiresSecondPassLayout ( ) )
{
ArrangedChildren . AddWidget ( AllottedGeometry . MakeChild ( SomeChild , SomeChild - > GetPosition ( ) - ViewOffset , SomeChild - > GetDesiredSizeForMarquee ( ) , GetZoomAmount ( ) ) ) ;
}
}
// Second pass nodes
for ( int32 ChildIndex = 0 ; ChildIndex < VisibleChildren . Num ( ) ; + + ChildIndex )
{
const TSharedRef < SNode > & SomeChild = VisibleChildren [ ChildIndex ] ;
if ( SomeChild - > RequiresSecondPassLayout ( ) )
{
SomeChild - > PerformSecondPassLayout ( NodeToWidgetLookup ) ;
ArrangedChildren . AddWidget ( AllottedGeometry . MakeChild ( SomeChild , SomeChild - > GetPosition ( ) - ViewOffset , SomeChild - > GetDesiredSizeForMarquee ( ) , GetZoomAmount ( ) ) ) ;
}
}
}
TSharedPtr < SWidget > SGraphPanel : : OnSummonContextMenu ( const FGeometry & MyGeometry , const FPointerEvent & MouseEvent )
{
//Editability is up to the user to consider for menu options
{
// If we didn't drag very far, summon a context menu.
// Figure out what's under the mouse: Node, Pin or just the Panel, and summon the context menu for that.
UEdGraphNode * NodeUnderCursor = NULL ;
UEdGraphPin * PinUnderCursor = NULL ;
{
FArrangedChildren ArrangedNodes ( EVisibility : : Visible ) ;
this - > ArrangeChildrenForContextMenuSummon ( MyGeometry , ArrangedNodes ) ;
const int32 HoveredNodeIndex = SWidget : : FindChildUnderMouse ( ArrangedNodes , MouseEvent ) ;
if ( HoveredNodeIndex ! = INDEX_NONE )
{
2014-08-25 12:51:49 -04:00
const FArrangedWidget & HoveredNode = ArrangedNodes [ HoveredNodeIndex ] ;
2014-09-11 07:02:40 -04:00
TSharedRef < SGraphNode > GraphNode = StaticCastSharedRef < SGraphNode > ( HoveredNode . Widget ) ;
TSharedPtr < SGraphNode > GraphSubNode = GraphNode - > GetNodeUnderMouse ( HoveredNode . Geometry , MouseEvent ) ;
GraphNode = GraphSubNode . IsValid ( ) ? GraphSubNode . ToSharedRef ( ) : GraphNode ;
2014-03-14 14:13:41 -04:00
NodeUnderCursor = GraphNode - > GetNodeObj ( ) ;
// Selection should switch to this code if it isn't already selected.
// When multiple nodes are selected, we do nothing, provided that the
// node for which the context menu is being created is in the selection set.
if ( ! SelectionManager . IsNodeSelected ( GraphNode - > GetObjectBeingDisplayed ( ) ) )
{
SelectionManager . SelectSingleNode ( GraphNode - > GetObjectBeingDisplayed ( ) ) ;
}
const TSharedPtr < SGraphPin > HoveredPin = GraphNode - > GetHoveredPin ( HoveredNode . Geometry , MouseEvent ) ;
if ( HoveredPin . IsValid ( ) )
{
PinUnderCursor = HoveredPin - > GetPinObj ( ) ;
}
}
}
const FVector2D NodeAddPosition = PanelCoordToGraphCoord ( MyGeometry . AbsoluteToLocal ( MouseEvent . GetScreenSpacePosition ( ) ) ) ;
TArray < UEdGraphPin * > NoSourcePins ;
2014-05-15 17:34:14 -04:00
return SummonContextMenu ( MouseEvent . GetScreenSpacePosition ( ) , NodeAddPosition , NodeUnderCursor , PinUnderCursor , NoSourcePins , MouseEvent . IsShiftDown ( ) ) ;
2014-03-14 14:13:41 -04:00
}
return TSharedPtr < SWidget > ( ) ;
}
bool SGraphPanel : : OnHandleLeftMouseRelease ( const FGeometry & MyGeometry , const FPointerEvent & MouseEvent )
{
2014-04-25 05:03:13 -04:00
TSharedPtr < SGraphPin > PreviewConnectionPin = PreviewConnectorFromPins . Num ( ) > 0 ? PreviewConnectorFromPins [ 0 ] . FindInGraphPanel ( * this ) : nullptr ;
if ( PreviewConnectionPin . IsValid ( ) & & IsEditable . Get ( ) )
2014-03-14 14:13:41 -04:00
{
TSet < TSharedRef < SWidget > > AllConnectors ;
for ( int32 ChildIndex = 0 ; ChildIndex < Children . Num ( ) ; + + ChildIndex )
{
//@FINDME:
TSharedRef < SGraphNode > ChildNode = StaticCastSharedRef < SGraphNode > ( Children [ ChildIndex ] ) ;
ChildNode - > GetPins ( AllConnectors ) ;
}
TMap < TSharedRef < SWidget > , FArrangedWidget > PinGeometries ;
this - > FindChildGeometries ( MyGeometry , AllConnectors , PinGeometries ) ;
bool bHandledDrop = false ;
TSet < UEdGraphNode * > NodeList ;
for ( TMap < TSharedRef < SWidget > , FArrangedWidget > : : TIterator SomePinIt ( PinGeometries ) ; ! bHandledDrop & & SomePinIt ; + + SomePinIt )
{
FArrangedWidget & PinWidgetGeometry = SomePinIt . Value ( ) ;
if ( PinWidgetGeometry . Geometry . IsUnderLocation ( MouseEvent . GetScreenSpacePosition ( ) ) )
{
SGraphPin & TargetPin = static_cast < SGraphPin & > ( PinWidgetGeometry . Widget . Get ( ) ) ;
2014-04-25 05:03:13 -04:00
if ( PreviewConnectionPin - > TryHandlePinConnection ( TargetPin ) )
2014-03-14 14:13:41 -04:00
{
NodeList . Add ( TargetPin . GetPinObj ( ) - > GetOwningNode ( ) ) ;
2014-04-25 05:03:13 -04:00
NodeList . Add ( PreviewConnectionPin - > GetPinObj ( ) - > GetOwningNode ( ) ) ;
2014-03-14 14:13:41 -04:00
}
bHandledDrop = true ;
}
}
// No longer make a connection for a pin; we just connected or failed to connect.
OnStopMakingConnection ( /*bForceStop=*/ true ) ;
return true ;
}
else
{
return false ;
}
}
void SGraphPanel : : OnDragEnter ( const FGeometry & MyGeometry , const FDragDropEvent & DragDropEvent )
{
2014-04-23 18:00:50 -04:00
TSharedPtr < FGraphEditorDragDropAction > DragConnectionOp = DragDropEvent . GetOperationAs < FGraphEditorDragDropAction > ( ) ;
if ( DragConnectionOp . IsValid ( ) )
2014-03-14 14:13:41 -04:00
{
DragConnectionOp - > SetHoveredGraph ( SharedThis ( this ) ) ;
}
}
void SGraphPanel : : OnDragLeave ( const FDragDropEvent & DragDropEvent )
{
2014-06-18 05:04:59 -04:00
TSharedPtr < FGraphEditorDragDropAction > Operation = DragDropEvent . GetOperationAs < FGraphEditorDragDropAction > ( ) ;
if ( Operation . IsValid ( ) )
2014-03-14 14:13:41 -04:00
{
2014-06-18 05:04:59 -04:00
Operation - > SetHoveredGraph ( TSharedPtr < SGraphPanel > ( NULL ) ) ;
2014-03-14 14:13:41 -04:00
}
2014-04-23 18:00:50 -04:00
else
2014-03-14 14:13:41 -04:00
{
2014-06-18 05:04:59 -04:00
TSharedPtr < FDecoratedDragDropOp > AssetOp = DragDropEvent . GetOperationAs < FDecoratedDragDropOp > ( ) ;
if ( AssetOp . IsValid ( ) )
2014-04-23 18:00:50 -04:00
{
AssetOp - > ResetToDefaultToolTip ( ) ;
}
2014-03-14 14:13:41 -04:00
}
}
FReply SGraphPanel : : OnDragOver ( const FGeometry & MyGeometry , const FDragDropEvent & DragDropEvent )
{
2014-04-23 18:00:50 -04:00
TSharedPtr < FDragDropOperation > Operation = DragDropEvent . GetOperation ( ) ;
if ( ! Operation . IsValid ( ) )
{
return FReply : : Unhandled ( ) ;
}
2014-06-18 05:04:59 -04:00
// Handle Read only graphs
if ( ! IsEditable . Get ( ) )
{
TSharedPtr < FGraphEditorDragDropAction > GraphDragDropOp = DragDropEvent . GetOperationAs < FGraphEditorDragDropAction > ( ) ;
if ( GraphDragDropOp . IsValid ( ) )
{
GraphDragDropOp - > SetDropTargetValid ( false ) ;
}
else
{
TSharedPtr < FDecoratedDragDropOp > AssetOp = DragDropEvent . GetOperationAs < FDecoratedDragDropOp > ( ) ;
if ( AssetOp . IsValid ( ) )
{
FText Tooltip = AssetOp - > GetHoverText ( ) ;
if ( Tooltip . IsEmpty ( ) )
{
Tooltip = NSLOCTEXT ( " GraphPanel " , " DragDropOperation " , " Graph is Read-Only " ) ;
}
AssetOp - > SetToolTip ( Tooltip , FEditorStyle : : GetBrush ( TEXT ( " Graph.ConnectorFeedback.Error " ) ) ) ;
}
}
return FReply : : Handled ( ) ;
}
2014-04-23 18:00:50 -04:00
if ( Operation - > IsOfType < FGraphEditorDragDropAction > ( ) )
2014-03-14 14:13:41 -04:00
{
PreviewConnectorEndpoint = MyGeometry . AbsoluteToLocal ( DragDropEvent . GetScreenSpacePosition ( ) ) ;
return FReply : : Handled ( ) ;
}
2014-04-23 18:00:50 -04:00
else if ( Operation - > IsOfType < FExternalDragOperation > ( ) )
2014-03-14 14:13:41 -04:00
{
return AssetUtil : : CanHandleAssetDrag ( DragDropEvent ) ;
}
2014-04-23 18:00:50 -04:00
else if ( Operation - > IsOfType < FAssetDragDropOp > ( ) )
2014-03-14 14:13:41 -04:00
{
if ( GraphObj ! = NULL & & GraphObj - > GetSchema ( ) )
{
2014-04-23 18:00:50 -04:00
TSharedPtr < FAssetDragDropOp > AssetOp = StaticCastSharedPtr < FAssetDragDropOp > ( Operation ) ;
2014-03-14 14:13:41 -04:00
bool bOkIcon = false ;
FString TooltipText ;
GraphObj - > GetSchema ( ) - > GetAssetsGraphHoverMessage ( AssetOp - > AssetData , GraphObj , TooltipText , bOkIcon ) ;
const FSlateBrush * TooltipIcon = bOkIcon ? FEditorStyle : : GetBrush ( TEXT ( " Graph.ConnectorFeedback.OK " ) ) : FEditorStyle : : GetBrush ( TEXT ( " Graph.ConnectorFeedback.Error " ) ) ; ;
2014-04-23 17:55:20 -04:00
AssetOp - > SetToolTip ( FText : : FromString ( TooltipText ) , TooltipIcon ) ;
2014-03-14 14:13:41 -04:00
}
return FReply : : Handled ( ) ;
}
else
{
return FReply : : Unhandled ( ) ;
}
}
FReply SGraphPanel : : OnDrop ( const FGeometry & MyGeometry , const FDragDropEvent & DragDropEvent )
{
const FVector2D NodeAddPosition = PanelCoordToGraphCoord ( MyGeometry . AbsoluteToLocal ( DragDropEvent . GetScreenSpacePosition ( ) ) ) ;
FSlateApplication : : Get ( ) . SetKeyboardFocus ( AsShared ( ) , EKeyboardFocusCause : : SetDirectly ) ;
2014-04-23 18:00:50 -04:00
TSharedPtr < FDragDropOperation > Operation = DragDropEvent . GetOperation ( ) ;
2014-06-18 05:04:59 -04:00
if ( ! Operation . IsValid ( ) | | ! IsEditable . Get ( ) )
2014-04-23 18:00:50 -04:00
{
return FReply : : Unhandled ( ) ;
}
if ( Operation - > IsOfType < FGraphEditorDragDropAction > ( ) )
2014-03-14 14:13:41 -04:00
{
check ( GraphObj ) ;
2014-04-23 18:00:50 -04:00
TSharedPtr < FGraphEditorDragDropAction > DragConn = StaticCastSharedPtr < FGraphEditorDragDropAction > ( Operation ) ;
2014-03-14 14:13:41 -04:00
return DragConn - > DroppedOnPanel ( SharedThis ( this ) , DragDropEvent . GetScreenSpacePosition ( ) , NodeAddPosition , * GraphObj ) ;
}
2014-04-23 18:00:50 -04:00
else if ( Operation - > IsOfType < FActorDragDropGraphEdOp > ( ) )
2014-03-14 14:13:41 -04:00
{
2014-04-23 18:00:50 -04:00
TSharedPtr < FActorDragDropGraphEdOp > ActorOp = StaticCastSharedPtr < FActorDragDropGraphEdOp > ( Operation ) ;
2014-03-14 14:13:41 -04:00
OnDropActor . ExecuteIfBound ( ActorOp - > Actors , GraphObj , NodeAddPosition ) ;
return FReply : : Handled ( ) ;
}
2014-04-23 18:00:50 -04:00
else if ( Operation - > IsOfType < FLevelDragDropOp > ( ) )
2014-03-14 14:13:41 -04:00
{
2014-04-23 18:00:50 -04:00
TSharedPtr < FLevelDragDropOp > LevelOp = StaticCastSharedPtr < FLevelDragDropOp > ( Operation ) ;
2014-03-14 14:13:41 -04:00
OnDropStreamingLevel . ExecuteIfBound ( LevelOp - > StreamingLevelsToDrop , GraphObj , NodeAddPosition ) ;
return FReply : : Handled ( ) ;
}
else
{
if ( GraphObj ! = NULL & & GraphObj - > GetSchema ( ) ! = NULL )
{
TArray < FAssetData > DroppedAssetData = AssetUtil : : ExtractAssetDataFromDrag ( DragDropEvent ) ;
if ( DroppedAssetData . Num ( ) > 0 )
{
GraphObj - > GetSchema ( ) - > DroppedAssetsOnGraph ( DroppedAssetData , NodeAddPosition , GraphObj ) ;
return FReply : : Handled ( ) ;
}
}
return FReply : : Unhandled ( ) ;
}
}
2014-05-15 17:34:14 -04:00
void SGraphPanel : : OnBeginMakingConnection ( UEdGraphPin * InOriginatingPin )
2014-03-14 14:13:41 -04:00
{
2014-05-15 17:34:14 -04:00
if ( InOriginatingPin ! = nullptr )
2014-04-25 05:03:13 -04:00
{
2014-05-15 17:34:14 -04:00
PreviewConnectorFromPins . Add ( InOriginatingPin ) ;
2014-04-25 05:03:13 -04:00
}
2014-03-14 14:13:41 -04:00
}
void SGraphPanel : : OnStopMakingConnection ( bool bForceStop )
{
if ( bForceStop | | ! bPreservePinPreviewConnection )
{
PreviewConnectorFromPins . Reset ( ) ;
bPreservePinPreviewConnection = false ;
}
}
void SGraphPanel : : PreservePinPreviewUntilForced ( )
{
bPreservePinPreviewConnection = true ;
}
/** Add a slot to the CanvasPanel dynamically */
void SGraphPanel : : AddGraphNode ( const TSharedRef < SNodePanel : : SNode > & NodeToAdd )
{
TSharedRef < SGraphNode > GraphNode = StaticCastSharedRef < SGraphNode > ( NodeToAdd ) ;
GraphNode - > SetOwner ( SharedThis ( this ) ) ;
const UEdGraphNode * Node = GraphNode - > GetNodeObj ( ) ;
2014-04-25 05:03:13 -04:00
if ( Node )
{
NodeGuidMap . Add ( Node - > NodeGuid , GraphNode ) ;
}
2014-03-14 14:13:41 -04:00
if ( Node & & Node - > IsA ( UEdGraphNode_Comment : : StaticClass ( ) ) )
{
SNodePanel : : AddGraphNodeToBack ( NodeToAdd ) ;
}
else
{
SNodePanel : : AddGraphNode ( NodeToAdd ) ;
}
}
void SGraphPanel : : RemoveAllNodes ( )
{
2014-04-25 05:03:13 -04:00
NodeGuidMap . Empty ( ) ;
2014-03-14 14:13:41 -04:00
CurrentHoveredPins . Empty ( ) ;
SNodePanel : : RemoveAllNodes ( ) ;
}
2014-05-15 17:34:14 -04:00
TSharedPtr < SWidget > SGraphPanel : : SummonContextMenu ( const FVector2D & WhereToSummon , const FVector2D & WhereToAddNode , UEdGraphNode * ForNode , UEdGraphPin * ForPin , const TArray < UEdGraphPin * > & DragFromPins , bool bShiftOperation )
2014-03-14 14:13:41 -04:00
{
if ( OnGetContextMenuFor . IsBound ( ) )
{
2014-05-15 17:34:14 -04:00
FGraphContextMenuArguments SpawnInfo ;
SpawnInfo . NodeAddPosition = WhereToAddNode ;
SpawnInfo . GraphNode = ForNode ;
SpawnInfo . GraphPin = ForPin ;
SpawnInfo . DragFromPins = DragFromPins ;
SpawnInfo . bShiftOperation = bShiftOperation ;
FActionMenuContent FocusedContent = OnGetContextMenuFor . Execute ( SpawnInfo ) ;
2014-03-14 14:13:41 -04:00
TSharedRef < SWidget > MenuContent =
SNew ( SBorder )
. BorderImage ( FEditorStyle : : GetBrush ( " Menu.Background " ) )
[
FocusedContent . Content
] ;
FSlateApplication : : Get ( ) . PushMenu (
AsShared ( ) ,
MenuContent ,
WhereToSummon ,
FPopupTransitionEffect ( FPopupTransitionEffect : : ContextMenu )
) ;
return FocusedContent . WidgetToFocus ;
}
return TSharedPtr < SWidget > ( ) ;
}
void SGraphPanel : : AttachGraphEvents ( TSharedPtr < SGraphNode > CreatedSubNode )
{
check ( CreatedSubNode . IsValid ( ) ) ;
CreatedSubNode - > SetIsEditable ( IsEditable ) ;
CreatedSubNode - > SetDoubleClickEvent ( OnNodeDoubleClicked ) ;
CreatedSubNode - > SetVerifyTextCommitEvent ( OnVerifyTextCommit ) ;
CreatedSubNode - > SetTextCommittedEvent ( OnTextCommitted ) ;
}
2014-05-15 17:34:14 -04:00
void SGraphPanel : : AddNode ( UEdGraphNode * Node )
2014-03-14 14:13:41 -04:00
{
TSharedPtr < SGraphNode > NewNode = FNodeFactory : : CreateNodeWidget ( Node ) ;
check ( NewNode . IsValid ( ) ) ;
2014-09-30 14:13:40 -04:00
const bool bWasUserAdded = ( UserAddedNodes . Find ( Node ) ! = nullptr ) ;
2014-03-14 14:13:41 -04:00
NewNode - > SetIsEditable ( IsEditable ) ;
NewNode - > SetDoubleClickEvent ( OnNodeDoubleClicked ) ;
NewNode - > SetVerifyTextCommitEvent ( OnVerifyTextCommit ) ;
NewNode - > SetTextCommittedEvent ( OnTextCommitted ) ;
NewNode - > SetDisallowedPinConnectionEvent ( OnDisallowedPinConnection ) ;
this - > AddGraphNode
(
NewNode . ToSharedRef ( )
) ;
if ( bWasUserAdded )
{
// Add the node to visible children, this allows focus to occur on sub-widgets for naming purposes.
VisibleChildren . Add ( NewNode . ToSharedRef ( ) ) ;
NewNode - > PlaySpawnEffect ( ) ;
2014-10-09 18:07:48 -04:00
NewNode - > UpdateGraphNode ( ) ;
2014-05-15 17:34:14 -04:00
NewNode - > RequestRenameOnSpawn ( ) ;
2014-03-14 14:13:41 -04:00
}
2014-10-09 18:07:48 -04:00
else
{
NewNode - > UpdateGraphNode ( ) ;
}
2014-03-14 14:13:41 -04:00
}
2014-04-25 05:03:13 -04:00
TSharedPtr < SGraphNode > SGraphPanel : : GetNodeWidgetFromGuid ( FGuid Guid ) const
{
return NodeGuidMap . FindRef ( Guid ) . Pin ( ) ;
}
2014-03-14 14:13:41 -04:00
void SGraphPanel : : Update ( )
{
// Add widgets for all the nodes that don't have one.
if ( GraphObj ! = NULL )
{
// Scan for all missing nodes
2014-09-30 14:13:40 -04:00
for ( int32 NodeIndex = 0 ; NodeIndex < GraphObj - > Nodes . Num ( ) ; + + NodeIndex )
2014-03-14 14:13:41 -04:00
{
UEdGraphNode * Node = GraphObj - > Nodes [ NodeIndex ] ;
if ( Node )
{
AddNode ( Node ) ;
}
else
{
UE_LOG ( LogGraphPanel , Warning , TEXT ( " Found NULL Node in GraphObj array. A node type has been deleted without creating an ActiveClassRedictor to K2Node_DeadClass. " ) ) ;
}
}
2014-09-30 14:13:40 -04:00
// find the last selection action, and execute it
for ( int32 ActionIndex = UserActions . Num ( ) - 1 ; ActionIndex > = 0 ; - - ActionIndex )
{
if ( UserActions [ ActionIndex ] . Action & GRAPHACTION_SelectNode )
{
DeferredSelectionTargetObjects . Empty ( ) ;
for ( const UEdGraphNode * Node : UserActions [ ActionIndex ] . Nodes )
{
DeferredSelectionTargetObjects . Add ( Node ) ;
}
break ;
}
}
2014-03-14 14:13:41 -04:00
}
else
{
RemoveAllNodes ( ) ;
}
// Clean out set of added nodes
UserAddedNodes . Empty ( ) ;
2014-09-30 14:13:40 -04:00
UserActions . Empty ( ) ;
2014-03-14 14:13:41 -04:00
// Invoke any delegate methods
OnUpdateGraphPanel . ExecuteIfBound ( ) ;
}
// Purges the existing visual representation (typically followed by an Update call in the next tick)
void SGraphPanel : : PurgeVisualRepresentation ( )
{
RemoveAllNodes ( ) ;
}
bool SGraphPanel : : IsNodeTitleVisible ( const class UEdGraphNode * Node , bool bRequestRename )
{
bool bTitleVisible = false ;
TSharedRef < SNode > * pWidget = NodeToWidgetLookup . Find ( Node ) ;
if ( pWidget ! = NULL )
{
TWeakPtr < SGraphNode > GraphNode = StaticCastSharedRef < SGraphNode > ( * pWidget ) ;
if ( GraphNode . IsValid ( ) & & ! HasMouseCapture ( ) )
{
FSlateRect TitleRect = GraphNode . Pin ( ) - > GetTitleRect ( ) ;
const FVector2D TopLeft = FVector2D ( TitleRect . Left , TitleRect . Top ) ;
const FVector2D BottomRight = FVector2D ( TitleRect . Right , TitleRect . Bottom ) ;
if ( IsRectVisible ( TopLeft , BottomRight ) )
{
bTitleVisible = true ;
}
else if ( bRequestRename )
{
bTitleVisible = JumpToRect ( TopLeft , BottomRight ) ;
}
if ( bTitleVisible & & bRequestRename )
{
GraphNode . Pin ( ) - > RequestRename ( ) ;
}
}
}
return bTitleVisible ;
}
bool SGraphPanel : : IsRectVisible ( const FVector2D & TopLeft , const FVector2D & BottomRight )
{
return TopLeft > = PanelCoordToGraphCoord ( FVector2D : : ZeroVector ) & & BottomRight < = PanelCoordToGraphCoord ( CachedAllottedGeometryScaledSize ) ;
}
bool SGraphPanel : : JumpToRect ( const FVector2D & TopLeft , const FVector2D & BottomRight )
{
ZoomTargetTopLeft = TopLeft ;
ZoomTargetBottomRight = BottomRight ;
bDeferredZoomingToFit = true ;
return true ;
}
void SGraphPanel : : JumpToNode ( const UEdGraphNode * JumpToMe , bool bRequestRename )
{
bDeferredZoomingToFit = false ;
if ( JumpToMe ! = NULL )
{
if ( bRequestRename )
{
TSharedRef < SNode > * pWidget = NodeToWidgetLookup . Find ( JumpToMe ) ;
if ( pWidget ! = NULL )
{
TSharedRef < SGraphNode > GraphNode = StaticCastSharedRef < SGraphNode > ( * pWidget ) ;
GraphNode - > RequestRename ( ) ;
}
}
// Select this node, and request that we jump to it.
SelectAndCenterObject ( JumpToMe , true ) ;
}
}
void SGraphPanel : : JumpToPin ( const UEdGraphPin * JumpToMe )
{
if ( JumpToMe ! = NULL )
{
JumpToNode ( JumpToMe - > GetOwningNode ( ) , false ) ;
}
}
2014-09-30 14:13:40 -04:00
void SGraphPanel : : OnGraphChanged ( const FEdGraphEditAction & EditAction )
2014-03-14 14:13:41 -04:00
{
2014-09-30 14:13:40 -04:00
if ( ( EditAction . Graph = = GraphObj ) & &
( EditAction . Nodes . Num ( ) > 0 ) & &
2014-03-14 14:13:41 -04:00
// We do not want to mark it as a UserAddedNode for graphs that do not currently have focus,
// this causes each one to want to do the effects and rename, which causes problems.
2014-09-30 14:13:40 -04:00
( HasKeyboardFocus ( ) | | HasFocusedDescendants ( ) ) )
2014-03-14 14:13:41 -04:00
{
2014-09-30 14:13:40 -04:00
int32 ActionIndex = UserActions . Num ( ) ;
if ( EditAction . Action & GRAPHACTION_AddNode )
{
for ( const UEdGraphNode * Node : EditAction . Nodes )
{
UserAddedNodes . Add ( Node , ActionIndex ) ;
}
}
UserActions . Add ( EditAction ) ;
2014-03-14 14:13:41 -04:00
}
}
void SGraphPanel : : NotifyGraphChanged ( const FEdGraphEditAction & EditAction )
{
// Forward call
OnGraphChanged ( EditAction ) ;
}
void SGraphPanel : : AddReferencedObjects ( FReferenceCollector & Collector )
{
Collector . AddReferencedObject ( GraphObj ) ;
Collector . AddReferencedObject ( GraphObjToDiff ) ;
2014-04-25 05:03:13 -04:00
}