2021-10-12 21:21:22 -04:00
// Copyright Epic Games, Inc. All Rights Reserved.
# include "Debugging/SKismetDebugTreeView.h"
# include "Debugging/SKismetDebuggingView.h"
# include "GenericPlatform/GenericPlatformApplicationMisc.h"
# include "HAL/PlatformApplicationMisc.h"
# include "PropertyInfoViewStyle.h"
# include "Widgets/Input/SHyperlink.h"
2021-11-18 14:37:34 -05:00
# include "Widgets/Images/SLayeredImage.h"
2021-10-12 21:21:22 -04:00
# include "Kismet2/BlueprintEditorUtils.h"
# include "Kismet2/Breakpoint.h"
# include "Kismet2/KismetEditorUtilities.h"
# include "Kismet2/KismetDebugUtilities.h"
2021-10-25 20:05:28 -04:00
# include "Kismet2/WatchedPin.h"
2021-10-12 21:21:22 -04:00
# include "BlueprintEditor.h"
# include "Styling/SlateColor.h"
# include "Styling/SlateIconFinder.h"
# include "Styling/StyleColors.h"
# include "GraphEditorSettings.h"
# include "SourceCodeNavigation.h"
# include "Widgets/Layout/SSpacer.h"
# include "Framework/MultiBox/MultiBoxBuilder.h"
# include "Framework/Commands/UIAction.h"
# include "Editor/EditorEngine.h"
2022-05-09 13:12:28 -04:00
# include "Styling/AppStyle.h"
2021-11-07 23:43:01 -05:00
# include "BlueprintEditorTabs.h"
# include "BlueprintDebugger.h"
2021-11-18 14:37:34 -05:00
# include "AssetThumbnail.h"
# include "ThumbnailRendering/ThumbnailManager.h"
2021-10-12 21:21:22 -04:00
# define LOCTEXT_NAMESPACE "DebugViewUI"
DEFINE_LOG_CATEGORY_STATIC ( LogBlueprintDebugTreeView , Log , All ) ;
//////////////////////////////////////////////////////////////////////////
/** The editor object */
extern UNREALED_API class UEditorEngine * GEditor ;
2021-11-07 23:43:01 -05:00
static const FText ViewInDebuggerText = LOCTEXT ( " ViewInDebugger " , " View in Blueprint Debugger " ) ;
static const FText ViewInDebuggerTooltipText = LOCTEXT ( " ViewInDebugger_Tooltip " , " Opens the Blueprint Debugger and starts watching this variable if it isn't already watched " ) ;
2021-11-18 14:37:34 -05:00
static constexpr float ThumbnailIconSize = 16.0f ;
static constexpr uint32 ThumbnailIconResolution = 16 ;
2021-11-07 23:43:01 -05:00
2021-10-12 21:21:22 -04:00
//////////////////////////////////////////////////////////////////////////
const FName SKismetDebugTreeView : : ColumnId_Name ( " Name " ) ;
const FName SKismetDebugTreeView : : ColumnId_Value ( " Value " ) ;
2021-11-07 23:43:01 -05:00
//////////////////////////////////////////////////////////////////////////
// SKismetDebugTreePropertyValueWidget
namespace
{
class SKismetDebugTreePropertyValueWidget : public SCompoundWidget
{
public :
SLATE_BEGIN_ARGS ( SKismetDebugTreePropertyValueWidget )
: _PropertyInfo ( nullptr )
, _TreeItem ( nullptr )
{ }
SLATE_ATTRIBUTE ( TSharedPtr < FPropertyInstanceInfo > , PropertyInfo )
SLATE_ARGUMENT ( FDebugTreeItemPtr , TreeItem )
SLATE_END_ARGS ( )
public :
void Construct ( const FArguments & InArgs , TSharedPtr < FString > InSearchString )
{
PropertyInfo = InArgs . _PropertyInfo ;
TreeItem = InArgs . _TreeItem ;
check ( TreeItem . IsValid ( ) ) ;
TSharedPtr < FPropertyInstanceInfo > Data = PropertyInfo . Get ( ) ;
if ( Data . IsValid ( ) )
{
2021-12-06 13:53:21 -05:00
if ( Data - > Property - > IsA < FObjectProperty > ( ) | | Data - > Property - > IsA < FInterfaceProperty > ( ) )
2021-11-07 23:43:01 -05:00
{
ChildSlot
[
SNew ( SHorizontalBox )
+ SHorizontalBox : : Slot ( )
. AutoWidth ( )
. VAlign ( VAlign_Center )
[
SNew ( PropertyInfoViewStyle : : STextHighlightOverlay )
. FullText ( this , & SKismetDebugTreePropertyValueWidget : : GetObjectValueText )
. HighlightText ( this , & SKismetDebugTreePropertyValueWidget : : GetHighlightText , InSearchString )
[
SNew ( STextBlock )
. ToolTipText ( this , & SKismetDebugTreePropertyValueWidget : : GetValueTooltipText )
. Text ( this , & SKismetDebugTreePropertyValueWidget : : GetObjectValueText )
]
]
+ SHorizontalBox : : Slot ( )
. AutoWidth ( )
. VAlign ( VAlign_Center )
[
SNew ( SSpacer )
. Size ( FVector2D ( 2.0f , 1.0f ) )
]
+ SHorizontalBox : : Slot ( )
. AutoWidth ( )
. VAlign ( VAlign_Center )
[
SNew ( SHyperlink )
. ToolTipText ( this , & SKismetDebugTreePropertyValueWidget : : GetClassLinkTooltipText )
. Text ( this , & SKismetDebugTreePropertyValueWidget : : GetObjectClassText )
. OnNavigate ( this , & SKismetDebugTreePropertyValueWidget : : OnNavigateToClass )
]
+ SHorizontalBox : : Slot ( )
. AutoWidth ( )
. VAlign ( VAlign_Center )
[
SNew ( SSpacer )
. Size ( FVector2D ( 2.0f , 1.0f ) )
]
+ SHorizontalBox : : Slot ( )
. AutoWidth ( )
. VAlign ( VAlign_Center )
[
SNew ( STextBlock )
. Text ( LOCTEXT ( " ObjectValueEnd " , " ) " ) )
]
] ;
}
else
{
ChildSlot
[
SNew ( PropertyInfoViewStyle : : STextHighlightOverlay )
. FullText ( this , & SKismetDebugTreePropertyValueWidget : : GetDescription )
. HighlightText ( this , & SKismetDebugTreePropertyValueWidget : : GetHighlightText , InSearchString )
[
SNew ( STextBlock )
. ToolTipText ( this , & SKismetDebugTreePropertyValueWidget : : GetDescription )
. Text ( this , & SKismetDebugTreePropertyValueWidget : : GetDescription )
]
] ;
}
}
}
private :
FText GetDescription ( ) const
{
return TreeItem - > GetDescription ( ) ;
}
FText GetHighlightText ( TSharedPtr < FString > InSearchString ) const
{
return TreeItem - > GetHighlightText ( InSearchString ) ;
}
FText GetObjectValueText ( ) const
{
TSharedPtr < FPropertyInstanceInfo > Data = PropertyInfo . Get ( ) ;
if ( Data . IsValid ( ) )
{
if ( const UObject * Object = Data - > Object . Get ( ) )
{
return FText : : Format ( LOCTEXT ( " ObjectValueBegin " , " {0} (Class: " ) , FText : : FromString ( Object - > GetName ( ) ) ) ;
}
}
return LOCTEXT ( " UnknownObjectValueBegin " , " [Unknown] (Class: " ) ;
}
FText GetValueTooltipText ( ) const
{
TSharedPtr < FPropertyInstanceInfo > Data = PropertyInfo . Get ( ) ;
if ( Data . IsValid ( ) )
{
// if this is an Object property, tooltip text should include its full name
if ( const UObject * Object = Data - > Object . Get ( ) )
{
return FText : : Format ( LOCTEXT ( " ObjectValueTooltip " , " {0} \n Class: {1} " ) ,
FText : : FromString ( Object - > GetFullName ( ) ) ,
FText : : FromString ( Object - > GetClass ( ) - > GetFullName ( ) ) ) ;
}
}
return GetDescription ( ) ;
}
FText GetClassLinkTooltipText ( ) const
{
TSharedPtr < FPropertyInstanceInfo > Data = PropertyInfo . Get ( ) ;
if ( Data . IsValid ( ) )
{
if ( const UObject * Object = Data - > Object . Get ( ) )
{
if ( UClass * Class = Object - > GetClass ( ) )
{
if ( UBlueprint * Blueprint = Cast < UBlueprint > ( Class - > ClassGeneratedBy ) )
{
return LOCTEXT ( " OpenBlueprintClass " , " Opens this Class in the Blueprint Editor " ) ;
}
else
{
// this is a native class
return LOCTEXT ( " OpenNativeClass " , " Navigates to this class' source file " ) ;
}
}
}
}
return LOCTEXT ( " UnknownClassName " , " [Unknown] " ) ;
}
FText GetObjectClassText ( ) const
{
TSharedPtr < FPropertyInstanceInfo > Data = PropertyInfo . Get ( ) ;
if ( Data . IsValid ( ) )
{
if ( const UObject * Object = Data - > Object . Get ( ) )
{
return FText : : FromString ( Object - > GetClass ( ) - > GetName ( ) ) ;
}
}
return LOCTEXT ( " UnknownClassName " , " [Unknown] " ) ;
}
void OnNavigateToClass ( ) const
{
TSharedPtr < FPropertyInstanceInfo > Data = PropertyInfo . Get ( ) ;
if ( Data . IsValid ( ) )
{
if ( const UObject * Object = Data - > Object . Get ( ) )
{
if ( UClass * Class = Object - > GetClass ( ) )
{
if ( UBlueprint * Blueprint = Cast < UBlueprint > ( Class - > ClassGeneratedBy ) )
{
GEditor - > GetEditorSubsystem < UAssetEditorSubsystem > ( ) - > OpenEditorForAsset ( Blueprint ) ;
}
else
{
// this is a native class
FSourceCodeNavigation : : NavigateToClass ( Class ) ;
}
}
}
}
}
FDebugTreeItemPtr TreeItem ;
TAttribute < TSharedPtr < FPropertyInstanceInfo > > PropertyInfo ;
} ;
}
2021-10-12 21:21:22 -04:00
//////////////////////////////////////////////////////////////////////////
// FDebugLineItem
uint16 FDebugLineItem : : ActiveTypeBitset = TNumericLimits < uint16 > : : Max ( ) ; // set all to active by default
FText FDebugLineItem : : GetName ( ) const
{
return FText : : GetEmpty ( ) ;
}
FText FDebugLineItem : : GetDisplayName ( ) const
{
return FText : : GetEmpty ( ) ;
}
FText FDebugLineItem : : GetDescription ( ) const
{
return FText : : GetEmpty ( ) ;
}
bool FDebugLineItem : : HasName ( ) const
{
return ! GetDisplayName ( ) . IsEmpty ( ) ;
}
bool FDebugLineItem : : HasValue ( ) const
{
return ! GetDescription ( ) . IsEmpty ( ) ;
}
void FDebugLineItem : : CopyNameToClipboard ( ) const
{
FPlatformApplicationMisc : : ClipboardCopy ( ToCStr ( GetDisplayName ( ) . ToString ( ) ) ) ;
}
void FDebugLineItem : : CopyValueToClipboard ( ) const
{
FPlatformApplicationMisc : : ClipboardCopy ( ToCStr ( GetDescription ( ) . ToString ( ) ) ) ;
}
TSharedRef < SWidget > FDebugLineItem : : GenerateNameWidget ( TSharedPtr < FString > InSearchString )
{
return SNew ( PropertyInfoViewStyle : : STextHighlightOverlay )
. FullText ( this , & FDebugLineItem : : GetDisplayName )
. HighlightText ( this , & FDebugLineItem : : GetHighlightText , InSearchString )
[
SNew ( STextBlock )
. ToolTipText ( this , & FDebugLineItem : : GetDisplayName )
. Text ( this , & FDebugLineItem : : GetDisplayName )
] ;
}
TSharedRef < SWidget > FDebugLineItem : : GenerateValueWidget ( TSharedPtr < FString > InSearchString )
{
return SNew ( PropertyInfoViewStyle : : STextHighlightOverlay )
. FullText ( this , & FDebugLineItem : : GetDescription )
. HighlightText ( this , & FDebugLineItem : : GetHighlightText , InSearchString )
[
SNew ( STextBlock )
. ToolTipText ( this , & FDebugLineItem : : GetDescription )
. Text ( this , & FDebugLineItem : : GetDescription )
] ;
}
2021-11-07 23:43:01 -05:00
void FDebugLineItem : : MakeMenu ( FMenuBuilder & MenuBuilder , bool bInDebuggerTab )
2021-10-12 21:21:22 -04:00
{
2021-12-02 15:06:00 -05:00
if ( HasName ( ) )
{
const FUIAction CopyName (
FExecuteAction : : CreateSP ( this , & FDebugLineItem : : CopyNameToClipboard ) ,
FCanExecuteAction : : CreateSP ( this , & FDebugLineItem : : HasName )
) ;
2021-10-12 21:21:22 -04:00
2021-12-02 15:06:00 -05:00
MenuBuilder . AddMenuEntry (
LOCTEXT ( " CopyName " , " Copy Name " ) ,
LOCTEXT ( " CopyName_ToolTip " , " Copy name to clipboard " ) ,
FSlateIcon ( ) ,
CopyName
) ;
}
2021-10-12 21:21:22 -04:00
2021-12-02 15:06:00 -05:00
if ( HasValue ( ) )
{
const FUIAction CopyValue (
FExecuteAction : : CreateSP ( this , & FDebugLineItem : : CopyValueToClipboard ) ,
FCanExecuteAction : : CreateSP ( this , & FDebugLineItem : : HasValue )
) ;
2021-10-12 21:21:22 -04:00
2021-12-02 15:06:00 -05:00
MenuBuilder . AddMenuEntry (
LOCTEXT ( " CopyValue " , " Copy Value " ) ,
LOCTEXT ( " CopyValue_ToolTip " , " Copy value to clipboard " ) ,
FSlateIcon ( ) ,
CopyValue
) ;
}
2021-10-25 20:05:28 -04:00
2021-11-07 23:43:01 -05:00
ExtendContextMenu ( MenuBuilder , bInDebuggerTab ) ;
2021-10-25 20:05:28 -04:00
}
2021-11-07 23:43:01 -05:00
void FDebugLineItem : : ExtendContextMenu ( class FMenuBuilder & MenuBuilder , bool bInDebuggerTab )
2021-10-25 20:05:28 -04:00
{
2021-10-12 21:21:22 -04:00
}
void FDebugLineItem : : UpdateSearch ( const FString & InSearchString , FDebugLineItem : : ESearchFlags SearchFlags )
{
const bool bIsRootNode = SearchFlags & SF_RootNode ;
const bool bIsContainerElement = SearchFlags & SF_ContainerElement ;
// Container elements share their parent's property name, so we shouldn't search them by name
bVisible = ( ! bIsContainerElement & & GetName ( ) . ToString ( ) . Contains ( InSearchString ) ) | |
GetDisplayName ( ) . ToString ( ) . Contains ( InSearchString ) | |
GetDescription ( ) . ToString ( ) . Contains ( InSearchString ) ;
// for root nodes, bParentsMatchSearch always matches bVisible
if ( bVisible | | bIsRootNode )
{
bParentsMatchSearch = bVisible ;
}
}
bool FDebugLineItem : : IsVisible ( )
{
return bVisible ;
}
bool FDebugLineItem : : DoParentsMatchSearch ( )
{
return bParentsMatchSearch ;
}
bool FDebugLineItem : : HasChildren ( ) const
{
return false ;
}
TSharedRef < SWidget > FDebugLineItem : : GetNameIcon ( )
{
2022-05-09 13:12:28 -04:00
static const FSlateBrush * CachedBrush = FAppStyle : : GetBrush ( TEXT ( " NoBrush " ) ) ;
2021-10-12 21:21:22 -04:00
return SNew ( SImage ) . Image ( CachedBrush ) ;
}
TSharedRef < SWidget > FDebugLineItem : : GetValueIcon ( )
{
2022-05-09 13:12:28 -04:00
static const FSlateBrush * CachedBrush = FAppStyle : : GetBrush ( TEXT ( " NoBrush " ) ) ;
2021-10-12 21:21:22 -04:00
return SNew ( SImage ) . Image ( CachedBrush ) ;
}
FText FDebugLineItem : : GetHighlightText ( const TSharedPtr < FString > InSearchString ) const
{
return FText : : FromString ( * InSearchString ) ;
}
UBlueprint * FDebugLineItem : : GetBlueprintForObject ( UObject * ParentObject )
{
if ( ParentObject = = nullptr )
{
return nullptr ;
}
if ( UBlueprint * ParentBlueprint = Cast < UBlueprint > ( ParentObject ) )
{
return ParentBlueprint ;
}
if ( UClass * ParentClass = ParentObject - > GetClass ( ) )
{
if ( UBlueprint * ParentBlueprint = Cast < UBlueprint > ( ParentClass - > ClassGeneratedBy ) )
{
return ParentBlueprint ;
}
}
// recursively walk up ownership hierarchy until we find the blueprint
return GetBlueprintForObject ( ParentObject - > GetOuter ( ) ) ;
}
UBlueprintGeneratedClass * FDebugLineItem : : GetClassForObject ( UObject * ParentObject )
{
if ( ParentObject ! = nullptr )
{
if ( UBlueprint * Blueprint = Cast < UBlueprint > ( ParentObject ) )
{
return Cast < UBlueprintGeneratedClass > ( * Blueprint - > GeneratedClass ) ;
}
else if ( UBlueprintGeneratedClass * Result = Cast < UBlueprintGeneratedClass > ( ParentObject ) )
{
return Result ;
}
else
{
return Cast < UBlueprintGeneratedClass > ( ParentObject - > GetClass ( ) ) ;
}
}
return nullptr ;
}
bool FDebugLineItem : : IsDebugLineTypeActive ( EDebugLineType Type )
{
const uint16 Mask = 1 < < Type ;
return ActiveTypeBitset & Mask ;
}
void FDebugLineItem : : OnDebugLineTypeActiveChanged ( ECheckBoxState CheckState , EDebugLineType Type )
{
const uint16 Mask = 1 < < Type ;
switch ( CheckState )
{
case ECheckBoxState : : Checked :
ActiveTypeBitset | = Mask ;
break ;
default :
ActiveTypeBitset & = ~ Mask ;
break ;
}
}
//////////////////////////////////////////////////////////////////////////
// ILineItemWithChildren
class FLineItemWithChildren : public FDebugLineItem
{
public :
FLineItemWithChildren ( EDebugLineType InType ) :
FDebugLineItem ( InType )
{ }
virtual ~ FLineItemWithChildren ( ) override = default ;
virtual bool HasChildren ( ) const override
{
return ! ChildrenMirrors . IsEmpty ( ) ;
}
virtual bool CanHaveChildren ( ) override { return true ; }
/** Pilot for Recursive Search */
bool SearchRecursive ( const FString & InSearchString , TSharedPtr < STreeView < FDebugTreeItemPtr > > DebugTreeView )
{
TArray < FLineItemWithChildren * > Parents ;
return SearchRecursive ( InSearchString , DebugTreeView , Parents ) ;
}
2021-11-07 23:43:01 -05:00
// ensures that ChildrenMirrors are set up for calls to EnsureChildIsAdded
virtual void GatherChildrenBase ( TArray < FDebugTreeItemPtr > & OutChildren , const FString & InSearchString , bool bRespectSearch ) override
{
Swap ( PrevChildrenMirrors , ChildrenMirrors ) ;
ChildrenMirrors . Empty ( ) ;
GatherChildren ( OutChildren , InSearchString , bRespectSearch ) ;
}
// allows FDebugTreeItemPtr to be stored in TSets
class FDebugTreeItemKeyFuncs
{
public :
typedef FDebugTreeItemPtr ElementType ;
typedef TTypeTraits < ElementType > : : ConstPointerType KeyInitType ;
typedef TCallTraits < ElementType > : : ParamType ElementInitType ;
enum { bAllowDuplicateKeys = false } ;
/**
* @ return The key used to index the given element .
*/
static FORCEINLINE KeyInitType GetSetKey ( ElementInitType Element )
{
return Element ;
}
/**
* @ return True if the keys match .
*/
static FORCEINLINE bool Matches ( KeyInitType A , KeyInitType B )
{
FDebugLineItem * APtr = A . Get ( ) ;
FDebugLineItem * BPtr = B . Get ( ) ;
if ( APtr & & BPtr )
{
return ( APtr - > Type = = BPtr - > Type ) & & APtr - > Compare ( BPtr ) ;
}
return APtr = = BPtr ;
}
/** Calculates a hash index for a key. */
static FORCEINLINE uint32 GetKeyHash ( KeyInitType Key )
{
if ( FDebugLineItem * KeyPtr = Key . Get ( ) )
{
return KeyPtr - > GetHash ( ) ;
}
return GetTypeHash ( Key ) ;
}
} ;
protected :
// Last frames cached children
TSet < FDebugTreeItemPtr , FDebugTreeItemKeyFuncs > PrevChildrenMirrors ;
// This frames children
TSet < FDebugTreeItemPtr , FDebugTreeItemKeyFuncs > ChildrenMirrors ;
/** @returns whether this item represents a container property */
virtual bool IsContainer ( ) const
{
return false ;
}
virtual void GatherChildren ( TArray < FDebugTreeItemPtr > & OutChildren , const FString & InSearchString , bool bRespectSearch ) { }
2021-10-12 21:21:22 -04:00
/**
* returns whether this node should be visible according to the users
* search query
*
* O ( number of recursive children )
*/
bool SearchRecursive ( const FString & InSearchString ,
TSharedPtr < STreeView < FDebugTreeItemPtr > > DebugTreeView ,
TArray < FLineItemWithChildren * > & Parents ,
ESearchFlags SearchFlags = SF_None )
{
bVisible = false ;
UpdateSearch ( InSearchString , SearchFlags ) ;
bool bChildMatch = false ;
Parents . Push ( this ) ;
ESearchFlags ChildSearchFlags = IsContainer ( ) ? SF_ContainerElement : SF_None ;
TArray < FDebugTreeItemPtr > Children ;
GatherChildrenBase ( Children , InSearchString , /*bRespectSearch =*/ false ) ;
for ( const FDebugTreeItemPtr & ChildRef : Children )
{
if ( ChildRef - > CanHaveChildren ( ) )
{
ChildRef - > bParentsMatchSearch = bParentsMatchSearch ;
FLineItemWithChildren * Child = StaticCast < FLineItemWithChildren * > ( ChildRef . Get ( ) ) ;
// check if the child has been seen already in parents.
// if it has, skip it. (avoids stack overflows)
if ( Parents . FindByPredicate (
[ Child ] ( const FLineItemWithChildren * Relative )
{
return ( Relative - > Type = = Child - > Type ) & & Relative - > Compare ( Child ) ;
}
) )
{
continue ;
}
// if any children need to expand, so should this
if ( Child - > SearchRecursive ( InSearchString , DebugTreeView , Parents , ChildSearchFlags ) )
{
bVisible = true ;
bChildMatch = true ;
}
}
else
{
ChildRef - > UpdateSearch ( InSearchString , ChildSearchFlags ) ;
// if any children need to expand, so should this
if ( ChildRef - > IsVisible ( ) )
{
bVisible = true ;
bChildMatch = true ;
}
}
}
Parents . Pop ( /*bAllowShrinking =*/ false ) ;
if ( bChildMatch )
{
2022-01-12 12:31:20 -05:00
DebugTreeView - > SetItemExpansion ( SharedThis ( this ) , true ) ;
2021-10-12 21:21:22 -04:00
}
return bVisible ;
}
/**
* Adds either Item or an identical node that was previously
* created ( present in ChildrenMirrors ) as a child to OutChildren .
*
* O ( 1 )
*/
void EnsureChildIsAdded ( TArray < FDebugTreeItemPtr > & OutChildren , const FDebugLineItem & Item , const FString & InSearchString , bool bRespectSearch )
{
const FDebugTreeItemPtr Shareable = MakeShareable ( Item . Duplicate ( ) ) ;
if ( FDebugTreeItemPtr * Found = PrevChildrenMirrors . Find ( Shareable ) )
{
FDebugTreeItemPtr FoundItem = * Found ;
FoundItem - > UpdateData ( Item ) ;
ChildrenMirrors . Add ( FoundItem ) ;
// only add item if it matches search
2021-11-18 14:37:34 -05:00
if ( ! bRespectSearch | | InSearchString . IsEmpty ( ) | | FoundItem - > IsVisible ( ) )
2021-10-12 21:21:22 -04:00
{
OutChildren . Add ( FoundItem ) ;
}
}
else
{
ChildrenMirrors . Add ( Shareable ) ;
OutChildren . Add ( Shareable ) ;
}
}
} ;
//////////////////////////////////////////////////////////////////////////
// FMessageLineItem
struct FMessageLineItem : public FDebugLineItem
{
protected :
FString Message ;
public :
// Message line
FMessageLineItem ( const FString & InMessage )
: FDebugLineItem ( DLT_Message )
, Message ( InMessage )
{
}
2021-11-07 23:43:01 -05:00
virtual FText GetDescription ( ) const override
2021-10-12 21:21:22 -04:00
{
2021-11-07 23:43:01 -05:00
return FText : : FromString ( Message ) ;
2021-10-12 21:21:22 -04:00
}
2021-11-07 23:43:01 -05:00
protected :
2021-10-12 21:21:22 -04:00
virtual FDebugLineItem * Duplicate ( ) const override
{
return new FMessageLineItem ( Message ) ;
}
2021-11-07 23:43:01 -05:00
virtual bool Compare ( const FDebugLineItem * BaseOther ) const override
2021-10-12 21:21:22 -04:00
{
2021-11-07 23:43:01 -05:00
FMessageLineItem * Other = ( FMessageLineItem * ) BaseOther ;
return Message = = Other - > Message ;
2021-10-12 21:21:22 -04:00
}
virtual uint32 GetHash ( ) override
{
return GetTypeHash ( Message ) ;
}
} ;
//////////////////////////////////////////////////////////////////////////
// FLatentActionLineItem
struct FLatentActionLineItem : public FDebugLineItem
{
protected :
int32 UUID ;
TWeakObjectPtr < UObject > ParentObjectRef ;
2021-11-07 23:43:01 -05:00
2021-10-12 21:21:22 -04:00
public :
FLatentActionLineItem ( int32 InUUID , UObject * ParentObject )
: FDebugLineItem ( DLT_LatentAction )
{
UUID = InUUID ;
check ( UUID ! = INDEX_NONE ) ;
ParentObjectRef = ParentObject ;
}
2021-11-07 23:43:01 -05:00
virtual TSharedRef < SWidget > GenerateNameWidget ( TSharedPtr < FString > InSearchString ) override ;
virtual TSharedRef < SWidget > GetNameIcon ( ) override ;
virtual FText GetDescription ( ) const override ;
2021-10-12 21:21:22 -04:00
protected :
2021-11-07 23:43:01 -05:00
virtual FDebugLineItem * Duplicate ( ) const override
{
return new FLatentActionLineItem ( UUID , ParentObjectRef . Get ( ) ) ;
}
2021-10-12 21:21:22 -04:00
virtual bool Compare ( const FDebugLineItem * BaseOther ) const override
{
FLatentActionLineItem * Other = ( FLatentActionLineItem * ) BaseOther ;
return ( ParentObjectRef . Get ( ) = = Other - > ParentObjectRef . Get ( ) ) & &
( UUID = = Other - > UUID ) ;
}
virtual uint32 GetHash ( ) override
{
return HashCombine ( GetTypeHash ( UUID ) , GetTypeHash ( ParentObjectRef ) ) ;
}
2021-11-07 23:43:01 -05:00
2021-10-12 21:21:22 -04:00
protected :
virtual FText GetDisplayName ( ) const override ;
void OnNavigateToLatentNode ( ) ;
class UEdGraphNode * FindAssociatedNode ( ) const ;
} ;
FText FLatentActionLineItem : : GetDescription ( ) const
{
if ( UObject * ParentObject = ParentObjectRef . Get ( ) )
{
if ( UWorld * World = GEngine - > GetWorldFromContextObject ( ParentObject , EGetWorldErrorMode : : ReturnNull ) )
{
FLatentActionManager & LatentActionManager = World - > GetLatentActionManager ( ) ;
return FText : : FromString ( LatentActionManager . GetDescription ( ParentObject , UUID ) ) ;
}
}
return LOCTEXT ( " nullptrObject " , " Object has been destroyed " ) ;
}
TSharedRef < SWidget > FLatentActionLineItem : : GenerateNameWidget ( TSharedPtr < FString > InSearchString )
{
return SNew ( PropertyInfoViewStyle : : STextHighlightOverlay )
. FullText ( this , & FLatentActionLineItem : : GetDisplayName )
. HighlightText ( this , & FLatentActionLineItem : : GetHighlightText , InSearchString )
[
SNew ( SHyperlink )
2022-05-09 13:12:28 -04:00
. Style ( FAppStyle : : Get ( ) , " HoverOnlyHyperlink " )
2021-10-12 21:21:22 -04:00
. OnNavigate ( this , & FLatentActionLineItem : : OnNavigateToLatentNode )
. Text ( this , & FLatentActionLineItem : : GetDisplayName )
. ToolTipText ( LOCTEXT ( " NavLatentActionLoc_Tooltip " , " Navigate to the latent action location " ) )
] ;
}
TSharedRef < SWidget > FLatentActionLineItem : : GetNameIcon ( )
{
return SNew ( SImage )
2022-05-09 13:12:28 -04:00
. Image ( FAppStyle : : GetBrush ( TEXT ( " Kismet.LatentActionIcon " ) ) ) ;
2021-10-12 21:21:22 -04:00
}
UEdGraphNode * FLatentActionLineItem : : FindAssociatedNode ( ) const
{
if ( UBlueprintGeneratedClass * Class = GetClassForObject ( ParentObjectRef . Get ( ) ) )
{
return Class - > GetDebugData ( ) . FindNodeFromUUID ( UUID ) ;
}
return nullptr ;
}
FText FLatentActionLineItem : : GetDisplayName ( ) const
{
FFormatNamedArguments Args ;
Args . Add ( TEXT ( " ID " ) , UUID ) ;
if ( UK2Node * Node = Cast < UK2Node > ( FindAssociatedNode ( ) ) )
{
Args . Add ( TEXT ( " Title " ) , Node - > GetCompactNodeTitle ( ) ) ;
return FText : : Format ( LOCTEXT ( " ID " , " {Title} (ID: {ID}) " ) , Args ) ;
}
else
{
return FText : : Format ( LOCTEXT ( " LatentAction " , " Latent action # {ID} " ) , Args ) ;
}
}
void FLatentActionLineItem : : OnNavigateToLatentNode ( )
{
if ( UEdGraphNode * Node = FindAssociatedNode ( ) )
{
FKismetEditorUtilities : : BringKismetToFocusAttentionOnObject ( Node ) ;
}
}
2021-11-07 23:43:01 -05:00
//////////////////////////////////////////////////////////////////////////
// FWatchChildLineItem
2021-10-12 21:21:22 -04:00
struct FWatchChildLineItem : public FLineItemWithChildren
{
protected :
2021-11-07 23:43:01 -05:00
TSharedRef < FPropertyInstanceInfo > Data ;
2021-10-25 20:05:28 -04:00
TWeakPtr < FDebugLineItem > ParentTreeItem ;
2021-10-12 21:21:22 -04:00
private :
bool bIconHovered = false ;
public :
2021-11-07 23:43:01 -05:00
FWatchChildLineItem ( TSharedRef < FPropertyInstanceInfo > Child , const FDebugTreeItemPtr & InParentTreeItem ) :
2021-10-12 21:21:22 -04:00
FLineItemWithChildren ( DLT_WatchChild ) ,
2021-10-25 20:05:28 -04:00
Data ( Child ) ,
ParentTreeItem ( InParentTreeItem )
2021-10-12 21:21:22 -04:00
{ }
2021-11-07 23:43:01 -05:00
virtual TSharedRef < SWidget > GenerateValueWidget ( TSharedPtr < FString > InSearchString ) override
2021-10-12 21:21:22 -04:00
{
2021-11-07 23:43:01 -05:00
return SNew ( SKismetDebugTreePropertyValueWidget , InSearchString )
. PropertyInfo ( this , & FWatchChildLineItem : : GetPropertyInfo )
. TreeItem ( AsShared ( ) ) ;
2021-10-12 21:21:22 -04:00
}
2021-11-07 23:43:01 -05:00
virtual void ExtendContextMenu ( FMenuBuilder & MenuBuilder , bool bInDebuggerTab ) override
2021-10-12 21:21:22 -04:00
{
2021-11-07 23:43:01 -05:00
//Navigate to Class source
2021-10-12 21:21:22 -04:00
2022-01-03 18:14:37 -05:00
// Only add watch options if this has a pin in it's parent chain
// (ok to discard the path, this only runs when a context menu is constructed)
TArray < FName > PathToProperty ;
if ( UEdGraphPin * PinParent = BuildPathToProperty ( PathToProperty ) )
{
//Add Watch
FUIAction AddThisWatch (
FExecuteAction : : CreateSP ( this , & FWatchChildLineItem : : AddWatch ) ,
FCanExecuteAction : : CreateSP ( this , & FWatchChildLineItem : : CanAddWatch )
) ;
2021-10-12 21:21:22 -04:00
2022-01-03 18:14:37 -05:00
MenuBuilder . AddMenuEntry (
LOCTEXT ( " AddPropertyWatch " , " Start Watching " ) ,
LOCTEXT ( " AddPropertyWatchTooltip " , " Start Watching This Variable " ) ,
FSlateIcon ( ) ,
AddThisWatch
) ;
2021-10-12 21:21:22 -04:00
2022-01-03 18:14:37 -05:00
//Add Watch
FUIAction ClearThisWatch (
FExecuteAction : : CreateSP ( this , & FWatchChildLineItem : : ClearWatch ) ,
FCanExecuteAction : : CreateSP ( this , & FWatchChildLineItem : : CanClearWatch )
) ;
2021-10-12 21:21:22 -04:00
2022-01-03 18:14:37 -05:00
MenuBuilder . AddMenuEntry (
LOCTEXT ( " ClearPropertyWatch " , " Stop Watching " ) ,
LOCTEXT ( " ClearPropertyWatchTooltip " , " Stop Watching This Variable " ) ,
FSlateIcon ( ) ,
ClearThisWatch
) ;
}
2021-10-12 21:21:22 -04:00
2021-11-07 23:43:01 -05:00
if ( ! bInDebuggerTab )
2021-10-12 21:21:22 -04:00
{
2021-11-07 23:43:01 -05:00
//View in Debugger
FUIAction ViewInDebugger (
FExecuteAction : : CreateSP ( this , & FWatchChildLineItem : : ViewInDebugger ) ,
FCanExecuteAction : : CreateSP ( this , & FWatchChildLineItem : : CanViewInDebugger )
) ;
2021-10-12 21:21:22 -04:00
2021-11-07 23:43:01 -05:00
MenuBuilder . AddMenuEntry (
ViewInDebuggerText ,
ViewInDebuggerTooltipText ,
FSlateIcon ( ) ,
ViewInDebugger
) ;
2021-10-12 21:21:22 -04:00
}
}
// uses the icon and color associated with the property type
virtual TSharedRef < SWidget > GetNameIcon ( ) override
{
FSlateColor BaseColor ;
FSlateColor SecondaryColor ;
FSlateBrush const * SecondaryIcon ;
const FSlateBrush * Icon = FBlueprintEditor : : GetVarIconAndColorFromProperty (
2021-11-07 23:43:01 -05:00
Data - > Property . Get ( ) ,
2021-10-12 21:21:22 -04:00
BaseColor ,
SecondaryIcon ,
SecondaryColor
) ;
2021-11-18 14:37:34 -05:00
TSharedPtr < SLayeredImage > LayeredImage ;
2021-10-12 21:21:22 -04:00
// make the icon a button so the user can open the asset in editor if there is one
2021-11-18 14:37:34 -05:00
TSharedRef < SWidget > NameIcon = SNew ( SButton )
2021-10-12 21:21:22 -04:00
. OnClicked ( this , & FWatchChildLineItem : : OnFocusAsset )
2022-05-09 13:12:28 -04:00
. ButtonStyle ( FAppStyle : : Get ( ) , " NoBorder " )
2021-10-12 21:21:22 -04:00
. ContentPadding ( 0.0f )
. OnHovered_Lambda (
[ & bIconHovered = bIconHovered ] ( ) { bIconHovered = true ; }
)
. OnUnhovered_Lambda (
[ & bIconHovered = bIconHovered ] ( ) { bIconHovered = false ; }
)
[
2021-10-25 20:05:28 -04:00
SNew ( SOverlay )
. ToolTipText ( this , & FWatchChildLineItem : : IconTooltipText )
+ SOverlay : : Slot ( )
. Padding ( FMargin ( 10.f , 0.f , 0.f , 0.f ) )
[
2021-11-18 14:37:34 -05:00
SAssignNew ( LayeredImage , SLayeredImage )
2021-10-25 20:05:28 -04:00
. Image ( Icon )
. ColorAndOpacity ( this , & FWatchChildLineItem : : ModifiedIconColor , BaseColor )
]
+ SOverlay : : Slot ( )
. HAlign ( HAlign_Left )
[
SNew ( SImage )
2022-05-09 13:12:28 -04:00
. Image ( FAppStyle : : GetBrush ( TEXT ( " Kismet.WatchIcon " ) ) )
2021-10-25 20:05:28 -04:00
. Visibility ( this , & FWatchChildLineItem : : GetWatchIconVisibility )
]
2021-10-12 21:21:22 -04:00
] ;
2021-11-18 14:37:34 -05:00
LayeredImage - > AddLayer (
SecondaryIcon ,
TAttribute < FSlateColor > : : CreateSP ( this , & FWatchChildLineItem : : ModifiedIconColor , SecondaryColor )
) ;
return NameIcon ;
}
virtual TSharedRef < SWidget > GetValueIcon ( ) override
{
if ( UObject * Object = Data - > Object . Get ( ) )
{
if ( Object - > IsAsset ( ) )
{
FAssetThumbnailConfig ThumbnailConfig ;
if ( FSlateApplication : : Get ( ) . InKismetDebuggingMode ( ) )
{
ThumbnailConfig . bForceGenericThumbnail = true ;
}
TSharedPtr < FAssetThumbnail > Thumb = MakeShared < FAssetThumbnail > ( Object , ThumbnailIconResolution , ThumbnailIconResolution , UThumbnailManager : : Get ( ) . GetSharedThumbnailPool ( ) ) ;
return SNew ( SButton )
. OnClicked ( this , & FWatchChildLineItem : : OnFocusAsset )
. ToolTipText ( this , & FWatchChildLineItem : : IconTooltipText )
2022-05-09 13:12:28 -04:00
. ButtonStyle ( FAppStyle : : Get ( ) , " NoBorder " )
2021-11-18 14:37:34 -05:00
[
SNew ( SBox )
. MaxDesiredHeight ( ThumbnailIconSize )
. MaxDesiredWidth ( ThumbnailIconSize )
[
Thumb - > MakeThumbnailWidget ( ThumbnailConfig )
]
] ;
}
}
return FDebugLineItem : : GetValueIcon ( ) ;
2021-10-12 21:21:22 -04:00
}
2021-11-07 23:43:01 -05:00
virtual FText GetDescription ( ) const override
2021-10-12 21:21:22 -04:00
{
2021-11-07 23:43:01 -05:00
const FString ValStr = Data - > Value . ToString ( ) ;
return FText : : FromString ( ValStr . Replace ( TEXT ( " \n " ) , TEXT ( " " ) ) ) ;
2021-10-25 20:05:28 -04:00
}
2021-10-12 21:21:22 -04:00
protected :
2021-11-07 23:43:01 -05:00
virtual FDebugLineItem * Duplicate ( ) const override
{
return new FWatchChildLineItem ( Data , ParentTreeItem . Pin ( ) ) ;
}
virtual bool Compare ( const FDebugLineItem * BaseOther ) const override
{
FWatchChildLineItem * Other = ( FWatchChildLineItem * ) BaseOther ;
return Data - > Property = = Other - > Data - > Property & &
Data - > DisplayName . CompareTo ( Other - > Data - > DisplayName ) = = 0 ;
}
virtual uint32 GetHash ( ) override
{
return HashCombine ( GetTypeHash ( Data - > Property ) , GetTypeHash ( Data - > DisplayName . ToString ( ) ) ) ;
}
virtual void UpdateData ( const FDebugLineItem & NewerData ) override
{
// Compare returns true even if the value or children of this node
// is different. use this function to update the data without completely
// replacing the node
FWatchChildLineItem & Other = ( FWatchChildLineItem & ) NewerData ;
Data = Other . Data ;
}
virtual FText GetName ( ) const override
{
return Data - > Name ;
}
virtual FText GetDisplayName ( ) const override
{
return Data - > DisplayName ;
}
// if data is pointing to an asset, get it's UPackage
const UPackage * GetDataPackage ( ) const
{
if ( Data - > Object . IsValid ( ) )
{
if ( const UBlueprintGeneratedClass * GeneratedClass = Cast < UBlueprintGeneratedClass > ( Data - > Object - > GetClass ( ) ) )
{
if ( const UPackage * Package = GeneratedClass - > GetPackage ( ) )
{
return Package ;
}
}
if ( const UPackage * Package = Data - > Object - > GetPackage ( ) )
{
return Package ;
}
}
return { } ;
}
2021-11-18 14:37:34 -05:00
bool CanOpenAsset ( ) const
{
if ( FSlateApplication : : Get ( ) . InKismetDebuggingMode ( ) )
{
if ( const UPackage * Package = GetDataPackage ( ) )
{
UObject * ReferencedAsset = Package - > FindAssetInPackage ( ) ;
// It is not safe to open asset editors for non-blueprint assets while stopped at a breakpoint
return Cast < UBlueprint > ( ReferencedAsset ) ! = nullptr ;
}
}
return true ;
}
2021-11-07 23:43:01 -05:00
// opens result of GetDataPackage in editor
FReply OnFocusAsset ( ) const
{
2021-11-18 14:37:34 -05:00
if ( ! CanOpenAsset ( ) )
{
return FReply : : Unhandled ( ) ;
}
2021-11-07 23:43:01 -05:00
const UPackage * Package = GetDataPackage ( ) ;
if ( ! Package )
{
return FReply : : Unhandled ( ) ;
}
const FString Path = Package - > GetPathName ( ) ;
if ( Path . IsEmpty ( ) )
{
return FReply : : Unhandled ( ) ;
}
GEditor - > GetEditorSubsystem < UAssetEditorSubsystem > ( ) - > OpenEditorForAsset ( Path ) ;
return FReply : : Handled ( ) ;
}
// returns the icon color given a precalculated color associated with this datatype.
// the color changes slightly based on whether it's null or a hovered button
FSlateColor ModifiedIconColor ( FSlateColor BaseColor ) const
{
FLinearColor LinearRGB = BaseColor . GetSpecifiedColor ( ) ;
// check if Data is a UObject
if ( CastField < FObjectPropertyBase > ( Data - > Property . Get ( ) ) )
{
FLinearColor LinearHSV = LinearRGB . LinearRGBToHSV ( ) ;
// if it's a null object, darken the icon so it's clear that it's not a button
if ( Data - > Object = = nullptr )
{
LinearHSV . B * = 0.5f ; // decrease value
LinearHSV . A * = 0.5f ; // decrease alpha
LinearRGB = LinearHSV . HSVToLinearRGB ( ) ;
}
// if the icon is hovered, lighten the icon
else if ( bIconHovered )
{
LinearHSV . B * = 2.f ; // increase value
LinearHSV . G * = 0.8f ; // decrease Saturation
LinearRGB = LinearHSV . HSVToLinearRGB ( ) ;
}
}
bool bPinWatched = false ;
TArray < FName > PathToProperty ;
if ( UEdGraphPin * PinToWatch = BuildPathToProperty ( PathToProperty ) )
{
bPinWatched = FKismetDebugUtilities : : IsPinBeingWatched ( FBlueprintEditorUtils : : FindBlueprintForNode ( PinToWatch - > GetOwningNode ( ) ) , PinToWatch , PathToProperty ) ;
}
if ( bPinWatched )
{
LinearRGB . A * = 0.3f ;
}
return LinearRGB ;
}
FText IconTooltipText ( ) const
{
const UPackage * Package = GetDataPackage ( ) ;
if ( Package )
{
2021-11-18 14:37:34 -05:00
if ( CanOpenAsset ( ) )
{
return FText : : Format ( LOCTEXT ( " OpenPackage " , " Open: {0} " ) , FText : : FromString ( Package - > GetName ( ) ) ) ;
}
2021-11-07 23:43:01 -05:00
}
return Data - > Type ;
}
virtual void GatherChildren ( TArray < FDebugTreeItemPtr > & OutChildren , const FString & InSearchString , bool bRespectSearch ) override
{
for ( const TSharedPtr < FPropertyInstanceInfo > & ChildData : Data - > Children )
{
EnsureChildIsAdded ( OutChildren , FWatchChildLineItem ( ChildData . ToSharedRef ( ) , AsShared ( ) ) , InSearchString , bRespectSearch ) ;
}
}
2021-10-12 21:21:22 -04:00
virtual bool IsContainer ( ) const override
{
2021-11-07 23:43:01 -05:00
return Data - > Property - > IsA < FSetProperty > ( ) | | Data - > Property - > IsA < FArrayProperty > ( ) | | Data - > Property - > IsA < FMapProperty > ( ) ;
2021-10-12 21:21:22 -04:00
}
2021-10-25 20:05:28 -04:00
EVisibility GetWatchIconVisibility ( ) const
{
bool bPinWatched = false ;
TArray < FName > PathToProperty ;
if ( UEdGraphPin * PinToWatch = BuildPathToProperty ( PathToProperty ) )
{
bPinWatched = FKismetDebugUtilities : : IsPinBeingWatched ( FBlueprintEditorUtils : : FindBlueprintForNode ( PinToWatch - > GetOwningNode ( ) ) , PinToWatch , PathToProperty ) ;
}
return bPinWatched ? EVisibility : : Visible : EVisibility : : Collapsed ;
}
2021-11-07 23:43:01 -05:00
TSharedPtr < FPropertyInstanceInfo > GetPropertyInfo ( ) const
{
return Data ;
}
2021-10-25 20:05:28 -04:00
void AddWatch ( ) ;
bool CanAddWatch ( ) const ;
void ClearWatch ( ) ;
bool CanClearWatch ( ) const ;
2021-11-07 23:43:01 -05:00
void ViewInDebugger ( ) ;
bool CanViewInDebugger ( ) const ;
2021-10-25 20:05:28 -04:00
UEdGraphPin * BuildPathToProperty ( TArray < FName > & OutPathToProperty ) const ;
2021-10-12 21:21:22 -04:00
} ;
/ / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / \
// FSelfWatchLineItem
2021-11-07 23:43:01 -05:00
2021-10-12 21:21:22 -04:00
struct FSelfWatchLineItem : public FLineItemWithChildren
{
protected :
// watches a UObject instead of a pin
TWeakObjectPtr < UObject > ObjectToWatch ;
public :
FSelfWatchLineItem ( UObject * Object ) :
2021-10-25 20:05:28 -04:00
FLineItemWithChildren ( DLT_SelfWatch ) ,
2021-10-12 21:21:22 -04:00
ObjectToWatch ( Object )
{ }
2021-11-07 23:43:01 -05:00
virtual TSharedRef < SWidget > GetNameIcon ( ) override
{
return SNew ( SImage )
2022-05-09 13:12:28 -04:00
. Image ( FAppStyle : : GetBrush ( TEXT ( " Kismet.WatchIcon " ) ) ) ;
2021-11-07 23:43:01 -05:00
}
protected :
virtual FDebugLineItem * Duplicate ( ) const override
{
return new FSelfWatchLineItem ( ObjectToWatch . Get ( ) ) ;
}
2021-10-12 21:21:22 -04:00
virtual bool Compare ( const FDebugLineItem * BaseOther ) const override
{
FSelfWatchLineItem * Other = ( FSelfWatchLineItem * ) BaseOther ;
return ( ObjectToWatch . Get ( ) = = Other - > ObjectToWatch . Get ( ) ) ;
}
virtual uint32 GetHash ( ) override
{
return GetTypeHash ( ObjectToWatch ) ;
}
2021-11-07 23:43:01 -05:00
virtual FText GetDisplayName ( ) const override
{
return LOCTEXT ( " SelfName " , " Self " ) ;
}
2021-10-12 21:21:22 -04:00
virtual void GatherChildren ( TArray < FDebugTreeItemPtr > & OutChildren , const FString & InSearchString , bool bRespectSearch ) override
{
if ( UObject * Object = ObjectToWatch . Get ( ) )
{
for ( TFieldIterator < FProperty > It ( Object - > GetClass ( ) ) ; It ; + + It )
{
TSharedPtr < FPropertyInstanceInfo > DebugInfo ;
FProperty * Property = * It ;
if ( Property - > HasAllPropertyFlags ( CPF_BlueprintVisible ) )
{
void * Value = Property - > ContainerPtrToValuePtr < void * > ( Object ) ;
FKismetDebugUtilities : : GetDebugInfoInternal ( DebugInfo , Property , Value ) ;
2021-11-07 23:43:01 -05:00
EnsureChildIsAdded ( OutChildren , FWatchChildLineItem ( DebugInfo . ToSharedRef ( ) , AsShared ( ) ) , InSearchString , bRespectSearch ) ;
2021-10-12 21:21:22 -04:00
}
}
}
}
} ;
//////////////////////////////////////////////////////////////////////////
// FWatchLineItem
struct FWatchLineItem : public FLineItemWithChildren
{
protected :
TWeakObjectPtr < UObject > ParentObjectRef ;
const FEdGraphPinReference ObjectRef ;
2021-11-29 19:11:53 -05:00
mutable TSharedPtr < FPropertyInstanceInfo > CachedPropertyInfo = nullptr ;
mutable FText CachedErrorString ;
2021-12-06 14:45:12 -05:00
const TArray < FName > PathToProperty ;
2021-10-12 21:21:22 -04:00
public :
FWatchLineItem ( const UEdGraphPin * PinToWatch , UObject * ParentObject )
: FLineItemWithChildren ( DLT_Watch )
, ObjectRef ( PinToWatch )
2021-10-25 20:05:28 -04:00
, PathToProperty ( )
{
ParentObjectRef = ParentObject ;
}
FWatchLineItem ( const UEdGraphPin * PinToWatch , UObject * ParentObject , const TArray < FName > & InPathToProperty )
: FLineItemWithChildren ( DLT_Watch )
, ObjectRef ( PinToWatch )
, PathToProperty ( InPathToProperty )
2021-10-12 21:21:22 -04:00
{
ParentObjectRef = ParentObject ;
}
2021-11-07 23:43:01 -05:00
virtual void ExtendContextMenu ( class FMenuBuilder & MenuBuilder , bool bInDebuggerTab ) override
2021-10-12 21:21:22 -04:00
{
if ( UEdGraphPin * WatchedPin = ObjectRef . Get ( ) )
{
2021-10-25 20:05:28 -04:00
FUIAction AddThisWatch (
FExecuteAction : : CreateSP ( this , & FWatchLineItem : : AddWatch ) ,
FCanExecuteAction : : CreateSP ( this , & FWatchLineItem : : CanAddWatch )
) ;
MenuBuilder . AddMenuEntry (
LOCTEXT ( " AddWatch " , " Start Watching " ) ,
LOCTEXT ( " AddWatch_ToolTip " , " Start watching this variable " ) ,
FSlateIcon ( ) ,
AddThisWatch ) ;
2021-10-12 21:21:22 -04:00
FUIAction ClearThisWatch (
2021-10-25 20:05:28 -04:00
FExecuteAction : : CreateSP ( this , & FWatchLineItem : : ClearWatch ) ,
FCanExecuteAction : : CreateSP ( this , & FWatchLineItem : : CanClearWatch )
2021-10-12 21:21:22 -04:00
) ;
MenuBuilder . AddMenuEntry (
LOCTEXT ( " ClearWatch " , " Stop watching " ) ,
LOCTEXT ( " ClearWatch_ToolTip " , " Stop watching this variable " ) ,
FSlateIcon ( ) ,
ClearThisWatch ) ;
2021-11-07 23:43:01 -05:00
if ( bInDebuggerTab )
{
FUIAction ViewInDebugger (
FExecuteAction : : CreateSP ( this , & FWatchLineItem : : ViewInDebugger ) ,
FCanExecuteAction : : CreateSP ( this , & FWatchLineItem : : CanViewInDebugger )
) ;
MenuBuilder . AddMenuEntry (
ViewInDebuggerText ,
ViewInDebuggerTooltipText ,
FSlateIcon ( ) ,
ViewInDebugger
) ;
}
2021-10-12 21:21:22 -04:00
}
}
2021-11-07 23:43:01 -05:00
const FEdGraphPinReference & GetPin ( ) const
{
return ObjectRef ;
}
2021-12-06 14:45:12 -05:00
const TArray < FName > & GetPathToProperty ( ) const
{
return PathToProperty ;
}
2021-11-07 23:43:01 -05:00
virtual FText GetDescription ( ) const override ;
virtual TSharedRef < SWidget > GenerateNameWidget ( TSharedPtr < FString > InSearchString ) override ;
virtual TSharedRef < SWidget > GenerateValueWidget ( TSharedPtr < FString > InSearchString ) override ;
2021-11-18 14:37:34 -05:00
virtual TSharedRef < SWidget > GetValueIcon ( ) override ;
2021-11-07 23:43:01 -05:00
virtual TSharedRef < SWidget > GetNameIcon ( ) override ;
2021-12-06 14:45:12 -05:00
/** Returns a SharedPtr to the debug info for the property being represented by this TreeItem */
TSharedPtr < FPropertyInstanceInfo > GetPropertyInfo ( ) const ;
2021-11-07 23:43:01 -05:00
protected :
virtual FDebugLineItem * Duplicate ( ) const override
{
return new FWatchLineItem ( ObjectRef . Get ( ) , ParentObjectRef . Get ( ) , PathToProperty ) ;
}
virtual bool Compare ( const FDebugLineItem * BaseOther ) const override
{
FWatchLineItem * Other = ( FWatchLineItem * ) BaseOther ;
return ( ParentObjectRef = = Other - > ParentObjectRef ) & &
( ObjectRef = = Other - > ObjectRef ) & &
( PathToProperty = = Other - > PathToProperty ) ;
}
virtual uint32 GetHash ( ) override
{
return HashCombine ( GetTypeHash ( ParentObjectRef ) , GetTypeHash ( ObjectRef ) ) ;
}
2021-10-12 21:21:22 -04:00
virtual void GatherChildren ( TArray < FDebugTreeItemPtr > & OutChildren , const FString & InSearchString , bool bRespectSearch ) override
{
2021-11-29 19:11:53 -05:00
TSharedPtr < FPropertyInstanceInfo > ThisDebugInfo = GetPropertyInfo ( ) ;
if ( ThisDebugInfo . IsValid ( ) )
2021-10-12 21:21:22 -04:00
{
2021-11-29 19:11:53 -05:00
for ( const TSharedPtr < FPropertyInstanceInfo > & ChildData : ThisDebugInfo - > Children )
2021-10-12 21:21:22 -04:00
{
2021-11-29 19:11:53 -05:00
EnsureChildIsAdded ( OutChildren , FWatchChildLineItem ( ChildData . ToSharedRef ( ) , AsShared ( ) ) , InSearchString , bRespectSearch ) ;
2021-10-12 21:21:22 -04:00
}
}
}
2021-11-07 23:43:01 -05:00
2021-10-12 21:21:22 -04:00
virtual FText GetDisplayName ( ) const override ;
2021-10-25 20:05:28 -04:00
const FSlateBrush * GetPinIcon ( ) const ;
2021-11-18 14:37:34 -05:00
const FSlateBrush * GetSecondaryPinIcon ( ) const ;
2021-10-25 20:05:28 -04:00
FSlateColor GetPinIconColor ( ) const ;
2021-11-18 14:37:34 -05:00
FSlateColor GetSecondaryPinIconColor ( ) const ;
2021-10-25 20:05:28 -04:00
EVisibility GetWatchIconVisibility ( ) const ;
FText GetTypename ( ) const ;
2021-10-12 21:21:22 -04:00
void OnNavigateToWatchLocation ( ) ;
2021-10-25 20:05:28 -04:00
private :
void AddWatch ( ) const
{
if ( UEdGraphPin * PinToWatch = ObjectRef . Get ( ) )
{
UBlueprint * ParentBlueprint = GetBlueprintForObject ( ParentObjectRef . Get ( ) ) ;
FKismetDebugUtilities : : AddPinWatch ( ParentBlueprint , FBlueprintWatchedPin ( PinToWatch , TArray < FName > ( PathToProperty ) ) ) ;
}
}
bool CanAddWatch ( ) const
{
if ( UEdGraphPin * PinToWatch = ObjectRef . Get ( ) )
{
UBlueprint * ParentBlueprint = GetBlueprintForObject ( ParentObjectRef . Get ( ) ) ;
return FKismetDebugUtilities : : CanWatchPin ( ParentBlueprint , PinToWatch , PathToProperty ) ;
}
return false ;
}
void ClearWatch ( ) const
{
if ( UEdGraphPin * PinToWatch = ObjectRef . Get ( ) )
{
UBlueprint * ParentBlueprint = GetBlueprintForObject ( ParentObjectRef . Get ( ) ) ;
TArray < FName > PathToPropertyCopy = PathToProperty ;
FKismetDebugUtilities : : RemovePinWatch ( ParentBlueprint , PinToWatch , MoveTemp ( PathToPropertyCopy ) ) ;
}
}
bool CanClearWatch ( ) const
{
if ( UEdGraphPin * PinToWatch = ObjectRef . Get ( ) )
{
UBlueprint * ParentBlueprint = GetBlueprintForObject ( ParentObjectRef . Get ( ) ) ;
return FKismetDebugUtilities : : IsPinBeingWatched ( ParentBlueprint , PinToWatch , PathToProperty ) ;
}
return false ;
}
2021-11-07 23:43:01 -05:00
void ViewInDebugger ( ) const
{
// If this isn't already watched, add it as a watch
if ( CanAddWatch ( ) )
{
AddWatch ( ) ;
}
2021-10-25 20:05:28 -04:00
2021-11-07 23:43:01 -05:00
FGlobalTabmanager : : Get ( ) - > TryInvokeTab ( FBlueprintEditorTabs : : BlueprintDebuggerID ) ;
FBlueprintEditorModule & BlueprintEditorModule = FModuleManager : : Get ( ) . LoadModuleChecked < FBlueprintEditorModule > ( TEXT ( " Kismet " ) ) ;
BlueprintEditorModule . GetBlueprintDebugger ( ) - > SetDebuggedBlueprint ( GetBlueprintForObject ( ParentObjectRef . Get ( ) ) ) ;
}
bool CanViewInDebugger ( ) const
{
if ( UEdGraphPin * PinToWatch = ObjectRef . Get ( ) )
{
UBlueprint * ParentBlueprint = GetBlueprintForObject ( ParentObjectRef . Get ( ) ) ;
return FKismetDebugUtilities : : IsPinBeingWatched ( ParentBlueprint , PinToWatch , PathToProperty ) | |
FKismetDebugUtilities : : CanWatchPin ( ParentBlueprint , PinToWatch , PathToProperty ) ;
}
return false ;
}
2021-11-18 14:37:34 -05:00
bool CanOpenAsset ( UObject * AssetObject ) const
{
if ( FSlateApplication : : Get ( ) . InKismetDebuggingMode ( ) )
{
// opening non-blueprint assets while stopped at a breakpoint is unsafe
return Cast < UBlueprint > ( AssetObject ) ! = nullptr ;
}
return false ;
}
FReply OpenEditorForAsset ( ) const
{
TSharedPtr < FPropertyInstanceInfo > PropertyInfo = GetPropertyInfo ( ) ;
if ( PropertyInfo . IsValid ( ) )
{
if ( UObject * Object = PropertyInfo - > Object . Get ( ) )
{
if ( Object - > IsAsset ( ) & & CanOpenAsset ( Object ) )
{
GEditor - > GetEditorSubsystem < UAssetEditorSubsystem > ( ) - > OpenEditorForAsset ( Object ) ;
return FReply : : Handled ( ) ;
}
}
}
return FReply : : Unhandled ( ) ;
}
FReply OpenEditorForType ( ) const
{
TSharedPtr < FPropertyInstanceInfo > PropertyInfo = GetPropertyInfo ( ) ;
if ( PropertyInfo . IsValid ( ) )
{
if ( UObject * Object = PropertyInfo - > Object . Get ( ) )
{
if ( UBlueprint * Blueprint = Cast < UBlueprint > ( PropertyInfo - > Object - > GetClass ( ) - > ClassGeneratedBy ) )
{
GEditor - > GetEditorSubsystem < UAssetEditorSubsystem > ( ) - > OpenEditorForAsset ( Blueprint ) ;
return FReply : : Handled ( ) ;
}
}
}
return FReply : : Unhandled ( ) ;
}
FText GetAssetThumbnailTooltip ( ) const
{
TSharedPtr < FPropertyInstanceInfo > PropertyInfo = GetPropertyInfo ( ) ;
if ( PropertyInfo . IsValid ( ) )
{
if ( UObject * Object = PropertyInfo - > Object . Get ( ) )
{
if ( CanOpenAsset ( Object ) )
{
return FText : : Format ( LOCTEXT ( " OpenPackage " , " Open: {0} " ) , FText : : FromString ( Object - > GetFullName ( ) ) ) ;
}
}
return PropertyInfo - > Type ;
}
return FText : : GetEmpty ( ) ;
}
FText GetIconTooltipText ( ) const
{
TSharedPtr < FPropertyInstanceInfo > PropertyInfo = GetPropertyInfo ( ) ;
if ( PropertyInfo . IsValid ( ) )
{
if ( UObject * Object = PropertyInfo - > Object . Get ( ) )
{
if ( UBlueprint * Blueprint = Cast < UBlueprint > ( Object - > GetClass ( ) - > ClassGeneratedBy ) )
{
return FText : : Format ( LOCTEXT ( " OpenPackage " , " Open: {0} " ) , FText : : FromString ( Blueprint - > GetFullName ( ) ) ) ;
}
}
return PropertyInfo - > Type ;
}
return FText : : GetEmpty ( ) ;
}
2021-10-12 21:21:22 -04:00
} ;
FText FWatchLineItem : : GetDisplayName ( ) const
{
if ( UEdGraphPin * PinToWatch = ObjectRef . Get ( ) )
{
if ( UBlueprint * Blueprint = GetBlueprintForObject ( ParentObjectRef . Get ( ) ) )
{
if ( FProperty * Property = FKismetDebugUtilities : : FindClassPropertyForPin ( Blueprint , PinToWatch ) )
{
2021-10-25 20:05:28 -04:00
FString PathString ;
for ( FName PropertyName : PathToProperty )
{
PathString . Append ( TEXT ( " / " ) + PropertyName . ToString ( ) ) ;
}
return FText : : FromString ( UEditorEngine : : GetFriendlyName ( Property ) + PathString ) ;
2021-10-12 21:21:22 -04:00
}
}
FFormatNamedArguments Args ;
2021-11-18 14:37:34 -05:00
Args . Add ( TEXT ( " PinWatchName " ) , PinToWatch - > GetDisplayName ( ) ) ;
2021-10-12 21:21:22 -04:00
return FText : : Format ( LOCTEXT ( " DisplayNameNoProperty " , " {PinWatchName} (no prop) " ) , Args ) ;
}
else
{
return FText : : GetEmpty ( ) ;
}
}
FText FWatchLineItem : : GetDescription ( ) const
{
if ( UEdGraphPin * PinToWatch = ObjectRef . Get ( ) )
{
// Try to determine the blueprint that generated the watch
UBlueprint * ParentBlueprint = GetBlueprintForObject ( ParentObjectRef . Get ( ) ) ;
// Find a valid property mapping and display the current value
UObject * ParentObject = ParentObjectRef . Get ( ) ;
if ( ( ParentBlueprint ! = ParentObject ) & & ( ParentBlueprint ! = nullptr ) )
{
2021-11-29 19:11:53 -05:00
TSharedPtr < FPropertyInstanceInfo > DebugInfo = GetPropertyInfo ( ) ;
if ( DebugInfo . IsValid ( ) )
2021-10-12 21:21:22 -04:00
{
2021-11-29 19:11:53 -05:00
const FString ValStr = DebugInfo - > Value . ToString ( ) ;
return FText : : FromString ( ValStr . Replace ( TEXT ( " \n " ) , TEXT ( " " ) ) ) ;
2021-10-12 21:21:22 -04:00
}
2021-11-29 19:11:53 -05:00
return CachedErrorString ;
2021-10-12 21:21:22 -04:00
}
}
return FText : : GetEmpty ( ) ;
}
TSharedRef < SWidget > FWatchLineItem : : GenerateNameWidget ( TSharedPtr < FString > InSearchString )
{
2021-11-18 14:37:34 -05:00
FText NodeName = LOCTEXT ( " UnknownNode " , " [Unknown] " ) ;
FText GraphName = LOCTEXT ( " UnknownGraph " , " [Unknown] " ) ;
if ( const UEdGraphPin * Pin = ObjectRef . Get ( ) )
{
if ( const UEdGraphNode * Node = Pin - > GetOwningNode ( ) )
{
NodeName = FText : : FromString ( Node - > GetName ( ) ) ;
if ( const UEdGraph * Graph = Node - > GetGraph ( ) )
{
GraphName = FText : : FromString ( Graph - > GetName ( ) ) ;
}
}
}
const FText ToolTipText = FText : : FormatNamed ( LOCTEXT ( " NavWatchLoc " , " Navigate to the watch location \n Graph: {GraphName} \n Node: {NodeName} " ) ,
TEXT ( " GraphName " ) , GraphName ,
TEXT ( " NodeName " ) , NodeName
) ;
2021-10-12 21:21:22 -04:00
return SNew ( PropertyInfoViewStyle : : STextHighlightOverlay )
. FullText ( this , & FWatchLineItem : : GetDisplayName )
. HighlightText ( this , & FWatchLineItem : : GetHighlightText , InSearchString )
[
SNew ( SHyperlink )
2022-05-09 13:12:28 -04:00
. Style ( FAppStyle : : Get ( ) , " HoverOnlyHyperlink " )
2021-10-12 21:21:22 -04:00
. OnNavigate ( this , & FWatchLineItem : : OnNavigateToWatchLocation )
. Text ( this , & FWatchLineItem : : GetDisplayName )
2021-11-18 14:37:34 -05:00
. ToolTipText ( ToolTipText )
2021-10-12 21:21:22 -04:00
] ;
}
2021-11-07 23:43:01 -05:00
TSharedRef < SWidget > FWatchLineItem : : GenerateValueWidget ( TSharedPtr < FString > InSearchString )
{
return SNew ( SKismetDebugTreePropertyValueWidget , InSearchString )
. PropertyInfo ( this , & FWatchLineItem : : GetPropertyInfo )
. TreeItem ( AsShared ( ) ) ;
}
2021-11-18 14:37:34 -05:00
TSharedRef < SWidget > FWatchLineItem : : GetValueIcon ( )
{
TSharedPtr < FPropertyInstanceInfo > PropertyInfo = GetPropertyInfo ( ) ;
if ( PropertyInfo . IsValid ( ) )
{
if ( UObject * Object = PropertyInfo - > Object . Get ( ) )
{
if ( Object - > IsAsset ( ) )
{
FAssetThumbnailConfig ThumbnailConfig ;
if ( FSlateApplication : : Get ( ) . InKismetDebuggingMode ( ) )
{
ThumbnailConfig . bForceGenericThumbnail = true ;
}
TSharedPtr < FAssetThumbnail > Thumb = MakeShared < FAssetThumbnail > ( Object , ThumbnailIconResolution , ThumbnailIconResolution , UThumbnailManager : : Get ( ) . GetSharedThumbnailPool ( ) ) ;
return SNew ( SButton )
. OnClicked ( this , & FWatchLineItem : : OpenEditorForAsset )
. ToolTipText ( this , & FWatchLineItem : : GetAssetThumbnailTooltip )
2022-05-09 13:12:28 -04:00
. ButtonStyle ( FAppStyle : : Get ( ) , " NoBorder " )
2021-11-18 14:37:34 -05:00
[
SNew ( SBox )
. MaxDesiredHeight ( ThumbnailIconSize )
. MaxDesiredWidth ( ThumbnailIconSize )
[
Thumb - > MakeThumbnailWidget ( ThumbnailConfig )
]
] ;
}
}
}
return FDebugLineItem : : GetValueIcon ( ) ;
}
2021-10-12 21:21:22 -04:00
// overlays the watch icon on top of a faded icon associated with the pin type
TSharedRef < SWidget > FWatchLineItem : : GetNameIcon ( )
{
2021-11-18 14:37:34 -05:00
TSharedPtr < SLayeredImage > LayeredImage ;
TSharedRef < SWidget > NameIcon = SNew ( SButton )
2022-05-09 13:12:28 -04:00
. ButtonStyle ( FAppStyle : : Get ( ) , " NoBorder " )
2021-11-18 14:37:34 -05:00
. ToolTipText ( this , & FWatchLineItem : : GetIconTooltipText )
. OnClicked ( this , & FWatchLineItem : : OpenEditorForType )
[
SNew ( SOverlay )
. ToolTipText ( this , & FWatchLineItem : : GetTypename )
+ SOverlay : : Slot ( )
2021-10-12 21:21:22 -04:00
. Padding ( FMargin ( 10.f , 0.f , 0.f , 0.f ) )
[
2021-11-18 14:37:34 -05:00
SAssignNew ( LayeredImage , SLayeredImage )
. Image ( this , & FWatchLineItem : : GetPinIcon )
. ColorAndOpacity ( this , & FWatchLineItem : : GetPinIconColor )
2021-10-12 21:21:22 -04:00
]
2021-11-18 14:37:34 -05:00
+ SOverlay : : Slot ( )
2021-10-12 21:21:22 -04:00
. HAlign ( HAlign_Left )
[
SNew ( SImage )
2022-05-09 13:12:28 -04:00
. Image ( FAppStyle : : GetBrush ( TEXT ( " Kismet.WatchIcon " ) ) )
2021-11-18 14:37:34 -05:00
. Visibility ( this , & FWatchLineItem : : GetWatchIconVisibility )
]
] ;
LayeredImage - > AddLayer (
TAttribute < const FSlateBrush * > ( this , & FWatchLineItem : : GetSecondaryPinIcon ) ,
TAttribute < FSlateColor > ( this , & FWatchLineItem : : GetSecondaryPinIconColor )
) ;
return NameIcon ;
2021-10-12 21:21:22 -04:00
}
2021-10-25 20:05:28 -04:00
const FSlateBrush * FWatchLineItem : : GetPinIcon ( ) const
{
2021-11-29 19:11:53 -05:00
TSharedPtr < FPropertyInstanceInfo > ThisDebugInfo = GetPropertyInfo ( ) ;
if ( ThisDebugInfo . IsValid ( ) )
2021-10-25 20:05:28 -04:00
{
2021-11-29 19:11:53 -05:00
FSlateColor BaseColor ;
FSlateColor SecondaryColor ;
FSlateBrush const * SecondaryIcon ;
const FSlateBrush * Icon = FBlueprintEditor : : GetVarIconAndColorFromProperty (
ThisDebugInfo - > Property . Get ( ) ,
BaseColor ,
SecondaryIcon ,
SecondaryColor
) ;
2021-10-25 20:05:28 -04:00
2021-11-29 19:11:53 -05:00
return Icon ;
2021-10-25 20:05:28 -04:00
}
2022-05-09 13:12:28 -04:00
return FAppStyle : : GetBrush ( TEXT ( " NoBrush " ) ) ;
2021-10-25 20:05:28 -04:00
}
2021-11-18 14:37:34 -05:00
const FSlateBrush * FWatchLineItem : : GetSecondaryPinIcon ( ) const
2021-10-25 20:05:28 -04:00
{
2021-11-29 19:11:53 -05:00
TSharedPtr < FPropertyInstanceInfo > ThisDebugInfo = GetPropertyInfo ( ) ;
if ( ThisDebugInfo . IsValid ( ) )
2021-10-25 20:05:28 -04:00
{
2021-11-29 19:11:53 -05:00
FSlateColor BaseColor ;
FSlateColor SecondaryColor ;
FSlateBrush const * SecondaryIcon ;
const FSlateBrush * Icon = FBlueprintEditor : : GetVarIconAndColorFromProperty (
ThisDebugInfo - > Property . Get ( ) ,
BaseColor ,
SecondaryIcon ,
SecondaryColor
) ;
2021-10-25 20:05:28 -04:00
2021-11-29 19:11:53 -05:00
return SecondaryIcon ;
2021-11-18 14:37:34 -05:00
}
2022-05-09 13:12:28 -04:00
return FAppStyle : : GetBrush ( TEXT ( " NoBrush " ) ) ;
2021-11-18 14:37:34 -05:00
}
FSlateColor FWatchLineItem : : GetPinIconColor ( ) const
{
FSlateColor PinIconColor = FLinearColor : : White ;
if ( UEdGraphPin * ObjectToFocus = ObjectRef . Get ( ) )
{
2021-11-29 19:11:53 -05:00
TSharedPtr < FPropertyInstanceInfo > ThisDebugInfo = GetPropertyInfo ( ) ;
if ( ThisDebugInfo . IsValid ( ) )
2021-11-18 14:37:34 -05:00
{
2021-11-29 19:11:53 -05:00
if ( const UEdGraphSchema * Schema = ObjectToFocus - > GetSchema ( ) )
2021-11-18 14:37:34 -05:00
{
2021-11-29 19:11:53 -05:00
PinIconColor = Schema - > GetPinTypeColor ( ObjectToFocus - > PinType ) ;
2021-11-18 14:37:34 -05:00
}
2021-11-29 19:11:53 -05:00
}
2021-11-18 14:37:34 -05:00
if ( FKismetDebugUtilities : : IsPinBeingWatched ( FBlueprintEditorUtils : : FindBlueprintForNode ( ObjectToFocus - > GetOwningNode ( ) ) , ObjectToFocus , PathToProperty ) )
{
FLinearColor Color = PinIconColor . GetSpecifiedColor ( ) ;
Color . A = 0.3f ;
PinIconColor = Color ;
}
}
return PinIconColor ;
}
FSlateColor FWatchLineItem : : GetSecondaryPinIconColor ( ) const
{
FSlateColor PinIconColor = FLinearColor : : White ;
if ( UEdGraphPin * ObjectToFocus = ObjectRef . Get ( ) )
{
2021-11-29 19:11:53 -05:00
TSharedPtr < FPropertyInstanceInfo > ThisDebugInfo = GetPropertyInfo ( ) ;
if ( ThisDebugInfo . IsValid ( ) )
2021-11-18 14:37:34 -05:00
{
2021-11-29 19:11:53 -05:00
if ( const UEdGraphSchema * Schema = ObjectToFocus - > GetSchema ( ) )
2021-11-18 14:37:34 -05:00
{
2021-11-29 19:11:53 -05:00
PinIconColor = Schema - > GetSecondaryPinTypeColor ( ObjectToFocus - > PinType ) ;
2021-10-25 20:05:28 -04:00
}
}
if ( FKismetDebugUtilities : : IsPinBeingWatched ( FBlueprintEditorUtils : : FindBlueprintForNode ( ObjectToFocus - > GetOwningNode ( ) ) , ObjectToFocus , PathToProperty ) )
{
FLinearColor Color = PinIconColor . GetSpecifiedColor ( ) ;
Color . A = 0.3f ;
PinIconColor = Color ;
}
}
return PinIconColor ;
}
EVisibility FWatchLineItem : : GetWatchIconVisibility ( ) const
{
if ( const UEdGraphPin * Pin = ObjectRef . Get ( ) )
{
return FKismetDebugUtilities : : IsPinBeingWatched ( FBlueprintEditorUtils : : FindBlueprintForNode ( Pin - > GetOwningNode ( ) ) , Pin , PathToProperty ) ?
EVisibility : : Visible :
EVisibility : : Collapsed ;
}
return EVisibility : : Collapsed ;
}
FText FWatchLineItem : : GetTypename ( ) const
{
2021-11-29 19:11:53 -05:00
TSharedPtr < FPropertyInstanceInfo > ThisDebugInfo = GetPropertyInfo ( ) ;
if ( ThisDebugInfo . IsValid ( ) )
2021-10-25 20:05:28 -04:00
{
2021-11-29 19:11:53 -05:00
return UEdGraphSchema_K2 : : TypeToText ( ThisDebugInfo - > Property . Get ( ) ) ;
2021-10-25 20:05:28 -04:00
}
return FText : : GetEmpty ( ) ;
}
2021-10-12 21:21:22 -04:00
void FWatchLineItem : : OnNavigateToWatchLocation ( )
{
if ( UEdGraphPin * ObjectToFocus = ObjectRef . Get ( ) )
{
FKismetEditorUtilities : : BringKismetToFocusAttentionOnPin ( ObjectToFocus ) ;
}
}
2021-11-07 23:43:01 -05:00
TSharedPtr < FPropertyInstanceInfo > FWatchLineItem : : GetPropertyInfo ( ) const
{
2021-11-29 19:11:53 -05:00
if ( CachedPropertyInfo . IsValid ( ) )
{
return CachedPropertyInfo ;
}
2021-11-07 23:43:01 -05:00
if ( UEdGraphPin * ObjectToFocus = ObjectRef . Get ( ) )
{
// Try to determine the blueprint that generated the watch
UBlueprint * ParentBlueprint = GetBlueprintForObject ( ParentObjectRef . Get ( ) ) ;
// Find a valid property mapping and display the current value
UObject * ParentObject = ParentObjectRef . Get ( ) ;
if ( ( ParentBlueprint ! = ParentObject ) & & ( ParentBlueprint ! = nullptr ) )
{
TSharedPtr < FPropertyInstanceInfo > DebugInfo ;
const FKismetDebugUtilities : : EWatchTextResult WatchStatus = FKismetDebugUtilities : : GetDebugInfo ( DebugInfo , ParentBlueprint , ParentObject , ObjectToFocus ) ;
2021-11-29 19:11:53 -05:00
switch ( WatchStatus )
2021-11-07 23:43:01 -05:00
{
2021-11-29 19:11:53 -05:00
case FKismetDebugUtilities : : EWTR_Valid :
{
check ( DebugInfo ) ;
2021-12-13 14:06:50 -05:00
if ( PathToProperty . IsEmpty ( ) )
{
CachedPropertyInfo = DebugInfo ;
}
else
{
CachedPropertyInfo = DebugInfo - > ResolvePathToProperty ( PathToProperty ) ;
}
2021-11-29 19:11:53 -05:00
return CachedPropertyInfo ;
}
case FKismetDebugUtilities : : EWTR_NotInScope :
CachedErrorString = LOCTEXT ( " NotInScope " , " Not in scope " ) ;
case FKismetDebugUtilities : : EWTR_NoProperty :
CachedErrorString = LOCTEXT ( " UnknownProperty " , " No debug data " ) ;
default :
case FKismetDebugUtilities : : EWTR_NoDebugObject :
CachedErrorString = LOCTEXT ( " NoDebugObject " , " No debug object " ) ;
2021-11-07 23:43:01 -05:00
}
}
}
return nullptr ;
}
2021-10-25 20:05:28 -04:00
//////////////////////////////////////////////////////////////////////////
// FWatchChildLineItem (some functions that need the definition of FWatchLineItem)
void FWatchChildLineItem : : AddWatch ( )
{
TArray < FName > PathToProperty ;
if ( UEdGraphPin * PinToWatch = BuildPathToProperty ( PathToProperty ) )
{
FKismetDebugUtilities : : AddPinWatch ( FBlueprintEditorUtils : : FindBlueprintForNode ( PinToWatch - > GetOwningNode ( ) ) , FBlueprintWatchedPin ( PinToWatch , MoveTemp ( PathToProperty ) ) ) ;
}
}
bool FWatchChildLineItem : : CanAddWatch ( ) const
{
TArray < FName > PathToProperty ;
if ( UEdGraphPin * PinToWatch = BuildPathToProperty ( PathToProperty ) )
{
return FKismetDebugUtilities : : CanWatchPin ( FBlueprintEditorUtils : : FindBlueprintForNode ( PinToWatch - > GetOwningNode ( ) ) , PinToWatch , PathToProperty ) ;
}
return false ;
}
void FWatchChildLineItem : : ClearWatch ( )
{
TArray < FName > PathToProperty ;
if ( UEdGraphPin * PinToWatch = BuildPathToProperty ( PathToProperty ) )
{
FKismetDebugUtilities : : RemovePinWatch ( FBlueprintEditorUtils : : FindBlueprintForNode ( PinToWatch - > GetOwningNode ( ) ) , PinToWatch , PathToProperty ) ;
}
}
bool FWatchChildLineItem : : CanClearWatch ( ) const
{
TArray < FName > PathToProperty ;
if ( UEdGraphPin * PinToWatch = BuildPathToProperty ( PathToProperty ) )
{
return FKismetDebugUtilities : : IsPinBeingWatched ( FBlueprintEditorUtils : : FindBlueprintForNode ( PinToWatch - > GetOwningNode ( ) ) , PinToWatch , PathToProperty ) ;
}
return false ;
}
2021-11-07 23:43:01 -05:00
void FWatchChildLineItem : : ViewInDebugger ( )
{
// If this isn't already watched, add it as a watch
if ( CanAddWatch ( ) )
{
AddWatch ( ) ;
}
TArray < FName > PathToProperty ;
if ( UEdGraphPin * PinToWatch = BuildPathToProperty ( PathToProperty ) )
{
UBlueprint * Blueprint = FBlueprintEditorUtils : : FindBlueprintForNode ( PinToWatch - > GetOwningNode ( ) ) ;
FGlobalTabmanager : : Get ( ) - > TryInvokeTab ( FBlueprintEditorTabs : : BlueprintDebuggerID ) ;
FBlueprintEditorModule & BlueprintEditorModule = FModuleManager : : Get ( ) . LoadModuleChecked < FBlueprintEditorModule > ( TEXT ( " Kismet " ) ) ;
BlueprintEditorModule . GetBlueprintDebugger ( ) - > SetDebuggedBlueprint ( Blueprint ) ;
}
}
bool FWatchChildLineItem : : CanViewInDebugger ( ) const
{
TArray < FName > PathToProperty ;
if ( UEdGraphPin * PinToWatch = BuildPathToProperty ( PathToProperty ) )
{
UBlueprint * Blueprint = FBlueprintEditorUtils : : FindBlueprintForNode ( PinToWatch - > GetOwningNode ( ) ) ;
return FKismetDebugUtilities : : IsPinBeingWatched ( Blueprint , PinToWatch , PathToProperty ) | | FKismetDebugUtilities : : CanWatchPin ( Blueprint , PinToWatch , PathToProperty ) ;
}
return false ;
}
2021-10-25 20:05:28 -04:00
UEdGraphPin * FWatchChildLineItem : : BuildPathToProperty ( TArray < FName > & OutPathToProperty ) const
{
UEdGraphPin * PinToWatch = nullptr ;
OutPathToProperty . Reset ( ) ;
2021-12-06 14:45:12 -05:00
auto AddPropertyToPath = [ & OutPathToProperty ] ( const TSharedRef < FPropertyInstanceInfo > & InPropertyInfo )
{
if ( InPropertyInfo - > bIsInContainer )
{
// display name of map elements is their key exported to text
OutPathToProperty . Emplace ( InPropertyInfo - > DisplayName . ToString ( ) ) ;
}
else
{
OutPathToProperty . Emplace ( InPropertyInfo - > Property - > GetAuthoredName ( ) ) ;
}
} ;
AddPropertyToPath ( Data ) ;
2021-10-25 20:05:28 -04:00
FDebugTreeItemPtr Parent = ParentTreeItem . Pin ( ) ;
while ( Parent . IsValid ( ) )
{
if ( Parent - > GetType ( ) = = DLT_Watch )
{
// this is a FWatchLineItem
TSharedPtr < FWatchLineItem > ParentAsWatch = StaticCastSharedPtr < FWatchLineItem > ( Parent ) ;
PinToWatch = ParentAsWatch - > GetPin ( ) . Get ( ) ;
2021-12-06 14:45:12 -05:00
// Add the original path to the front of ours (we're still constructing it backwards)
const TArray < FName > & ParentPath = ParentAsWatch - > GetPathToProperty ( ) ;
for ( int32 PathIndex = ParentPath . Num ( ) - 1 ; PathIndex > = 0 ; - - PathIndex )
{
OutPathToProperty . Emplace ( ParentPath [ PathIndex ] ) ;
}
2021-10-25 20:05:28 -04:00
break ;
}
if ( Parent - > GetType ( ) = = DLT_WatchChild )
{
// This is a FWatchChildLineItem
TSharedPtr < FWatchChildLineItem > ParentAsChild = StaticCastSharedPtr < FWatchChildLineItem > ( Parent ) ;
2021-12-06 14:45:12 -05:00
AddPropertyToPath ( ParentAsChild - > Data ) ;
2021-10-25 20:05:28 -04:00
Parent = ParentAsChild - > ParentTreeItem . Pin ( ) ;
}
else
{
Parent . Reset ( ) ;
}
}
// Reverse the array because we built it backwards
Algo : : Reverse ( OutPathToProperty ) ;
return PinToWatch ;
}
2021-10-12 21:21:22 -04:00
//////////////////////////////////////////////////////////////////////////
// FBreakpointLineItem
struct FBreakpointLineItem : public FDebugLineItem
{
protected :
TWeakObjectPtr < UObject > ParentObjectRef ;
TSoftObjectPtr < UEdGraphNode > BreakpointNode ;
public :
FBreakpointLineItem ( TSoftObjectPtr < UEdGraphNode > BreakpointToWatch , UObject * ParentObject )
: FDebugLineItem ( DLT_Breakpoint )
{
BreakpointNode = BreakpointToWatch ;
ParentObjectRef = ParentObject ;
}
2021-11-07 23:43:01 -05:00
virtual TSharedRef < SWidget > GenerateNameWidget ( TSharedPtr < FString > InSearchString ) override
2021-10-12 21:21:22 -04:00
{
2021-11-07 23:43:01 -05:00
return SNew ( PropertyInfoViewStyle : : STextHighlightOverlay )
. FullText ( this , & FBreakpointLineItem : : GetDisplayName )
. HighlightText ( this , & FBreakpointLineItem : : GetHighlightText , InSearchString )
[
SNew ( SHyperlink )
2022-05-09 13:12:28 -04:00
. Style ( FAppStyle : : Get ( ) , " HoverOnlyHyperlink " )
2021-11-07 23:43:01 -05:00
. Text ( this , & FBreakpointLineItem : : GetDisplayName )
. ToolTipText ( LOCTEXT ( " NavBreakpointLoc " , " Navigate to the breakpoint location " ) )
. OnNavigate ( this , & FBreakpointLineItem : : OnNavigateToBreakpointLocation )
] ;
2021-10-12 21:21:22 -04:00
}
2021-11-07 23:43:01 -05:00
virtual void ExtendContextMenu ( class FMenuBuilder & MenuBuilder , bool bInDebuggerTab ) override
2021-10-12 21:21:22 -04:00
{
FBlueprintBreakpoint * Breakpoint = GetBreakpoint ( ) ;
const UBlueprint * ParentBlueprint = GetBlueprintForObject ( ParentObjectRef . Get ( ) ) ;
// By default, we don't allow actions to execute when in debug mode.
// Create an empty action to always allow execution for these commands (they are allowed in debug mode)
FCanExecuteAction AlwaysAllowExecute ;
if ( Breakpoint ! = nullptr )
{
const bool bNewEnabledState = ! Breakpoint - > IsEnabledByUser ( ) ;
FUIAction ToggleThisBreakpoint (
2021-10-25 20:05:28 -04:00
FExecuteAction : : CreateSP ( this , & FBreakpointLineItem : : ToggleBreakpoint ) ,
2021-10-12 21:21:22 -04:00
AlwaysAllowExecute
) ;
if ( bNewEnabledState )
{
// Enable
MenuBuilder . AddMenuEntry (
LOCTEXT ( " EnableBreakpoint " , " Enable breakpoint " ) ,
LOCTEXT ( " EnableBreakpoint_ToolTip " , " Enable this breakpoint; the debugger will appear when this node is about to be executed. " ) ,
FSlateIcon ( ) ,
ToggleThisBreakpoint ) ;
}
else
{
// Disable
MenuBuilder . AddMenuEntry (
LOCTEXT ( " DisableBreakpoint " , " Disable breakpoint " ) ,
LOCTEXT ( " DisableBreakpoint_ToolTip " , " Disable this breakpoint. " ) ,
FSlateIcon ( ) ,
ToggleThisBreakpoint ) ;
}
}
if ( ( Breakpoint ! = nullptr ) & & ( ParentBlueprint ! = nullptr ) )
{
FUIAction ClearThisBreakpoint (
2021-10-25 20:05:28 -04:00
FExecuteAction : : CreateSP ( this , & FBreakpointLineItem : : ClearBreakpoint ) ,
2021-10-12 21:21:22 -04:00
AlwaysAllowExecute
) ;
MenuBuilder . AddMenuEntry (
LOCTEXT ( " ClearBreakpoint " , " Remove breakpoint " ) ,
LOCTEXT ( " ClearBreakpoint_ToolTip " , " Remove the breakpoint from this node. " ) ,
FSlateIcon ( ) ,
ClearThisBreakpoint ) ;
}
}
virtual TSharedRef < SWidget > GetNameIcon ( ) override
{
return SNew ( SButton )
. OnClicked ( this , & FBreakpointLineItem : : OnUserToggledEnabled )
. ToolTipText ( LOCTEXT ( " ToggleBreakpointButton_ToolTip " , " Toggle this breakpoint " ) )
2022-05-09 13:12:28 -04:00
. ButtonStyle ( FAppStyle : : Get ( ) , " NoBorder " )
2021-10-12 21:21:22 -04:00
. ContentPadding ( 0.0f )
[
SNew ( SImage )
. Image ( this , & FBreakpointLineItem : : GetStatusImage )
. ToolTipText ( this , & FBreakpointLineItem : : GetStatusTooltip )
] ;
}
2021-11-07 23:43:01 -05:00
protected :
FBlueprintBreakpoint * GetBreakpoint ( ) const
{
if ( UEdGraphNode * Node = BreakpointNode . Get ( ) )
{
if ( const UBlueprint * Blueprint = GetBlueprintForObject ( Node ) )
{
return FKismetDebugUtilities : : FindBreakpointForNode ( Node , Blueprint ) ;
}
}
return nullptr ;
}
virtual FDebugLineItem * Duplicate ( ) const override
{
return new FBreakpointLineItem ( BreakpointNode , ParentObjectRef . Get ( ) ) ;
}
virtual bool Compare ( const FDebugLineItem * BaseOther ) const override
{
FBreakpointLineItem * Other = ( FBreakpointLineItem * ) BaseOther ;
return ( ParentObjectRef . Get ( ) = = Other - > ParentObjectRef . Get ( ) ) & &
( BreakpointNode = = Other - > BreakpointNode ) ;
}
virtual uint32 GetHash ( ) override
{
return HashCombine ( GetTypeHash ( ParentObjectRef ) , GetTypeHash ( BreakpointNode ) ) ;
}
2021-10-12 21:21:22 -04:00
virtual FText GetDisplayName ( ) const override ;
2021-10-25 20:05:28 -04:00
private :
void ToggleBreakpoint ( ) const
{
if ( FBlueprintBreakpoint * Breakpoint = GetBreakpoint ( ) )
{
FKismetDebugUtilities : : SetBreakpointEnabled ( * Breakpoint , ! Breakpoint - > IsEnabled ( ) ) ;
}
}
void ClearBreakpoint ( ) const
{
if ( UEdGraphNode * Node = BreakpointNode . Get ( ) )
{
if ( UBlueprint * Blueprint = GetBlueprintForObject ( Node ) )
{
FKismetDebugUtilities : : RemoveBreakpointFromNode ( Node , Blueprint ) ;
}
}
}
2021-10-12 21:21:22 -04:00
FReply OnUserToggledEnabled ( ) ;
void OnNavigateToBreakpointLocation ( ) ;
const FSlateBrush * GetStatusImage ( ) const ;
FText GetStatusTooltip ( ) const ;
} ;
FText FBreakpointLineItem : : GetDisplayName ( ) const
{
if ( FBlueprintBreakpoint * MyBreakpoint = GetBreakpoint ( ) )
{
return MyBreakpoint - > GetLocationDescription ( ) ;
}
return FText : : GetEmpty ( ) ;
}
FReply FBreakpointLineItem : : OnUserToggledEnabled ( )
{
if ( FBlueprintBreakpoint * MyBreakpoint = GetBreakpoint ( ) )
{
FKismetDebugUtilities : : SetBreakpointEnabled ( * MyBreakpoint , ! MyBreakpoint - > IsEnabledByUser ( ) ) ;
}
return FReply : : Handled ( ) ;
}
void FBreakpointLineItem : : OnNavigateToBreakpointLocation ( )
{
if ( FBlueprintBreakpoint * MyBreakpoint = GetBreakpoint ( ) )
{
FKismetEditorUtilities : : BringKismetToFocusAttentionOnObject ( MyBreakpoint - > GetLocation ( ) ) ;
}
}
const FSlateBrush * FBreakpointLineItem : : GetStatusImage ( ) const
{
if ( FBlueprintBreakpoint * MyBreakpoint = GetBreakpoint ( ) )
{
if ( MyBreakpoint - > IsEnabledByUser ( ) )
{
2022-05-09 13:12:28 -04:00
return FAppStyle : : GetBrush ( FKismetDebugUtilities : : IsBreakpointValid ( * MyBreakpoint ) ? TEXT ( " Kismet.Breakpoint.EnabledAndValid " ) : TEXT ( " Kismet.Breakpoint.EnabledAndInvalid " ) ) ;
2021-10-12 21:21:22 -04:00
}
else
{
2022-05-09 13:12:28 -04:00
return FAppStyle : : GetBrush ( TEXT ( " Kismet.Breakpoint.Disabled " ) ) ;
2021-10-12 21:21:22 -04:00
}
}
2022-05-09 13:12:28 -04:00
return FAppStyle : : GetDefaultBrush ( ) ;
2021-10-12 21:21:22 -04:00
}
FText FBreakpointLineItem : : GetStatusTooltip ( ) const
{
if ( FBlueprintBreakpoint * MyBreakpoint = GetBreakpoint ( ) )
{
if ( ! FKismetDebugUtilities : : IsBreakpointValid ( * MyBreakpoint ) )
{
return LOCTEXT ( " Breakpoint_NoHit " , " This breakpoint will not be hit because its node generated no code " ) ;
}
else
{
return MyBreakpoint - > IsEnabledByUser ( ) ? LOCTEXT ( " ActiveBreakpoint " , " Active breakpoint " ) : LOCTEXT ( " InactiveBreakpoint " , " Inactive breakpoint " ) ;
}
}
else
{
return LOCTEXT ( " NoBreakpoint " , " No Breakpoint " ) ;
}
}
//////////////////////////////////////////////////////////////////////////
// FTraceStackParentItem
class FBreakpointParentItem : public FLineItemWithChildren
{
public :
// The parent object
TWeakObjectPtr < UBlueprint > Blueprint ;
FBreakpointParentItem ( TWeakObjectPtr < UBlueprint > InBlueprint )
: FLineItemWithChildren ( DLT_BreakpointParent )
, Blueprint ( InBlueprint )
{
}
2021-11-07 23:43:01 -05:00
virtual void ExtendContextMenu ( FMenuBuilder & MenuBuilder , bool bInDebuggerTab ) override
2021-10-12 21:21:22 -04:00
{
if ( FKismetDebugUtilities : : BlueprintHasBreakpoints ( Blueprint . Get ( ) ) )
{
const FUIAction ClearAllBreakpoints (
2021-10-25 20:05:28 -04:00
FExecuteAction : : CreateSP ( this , & FBreakpointParentItem : : ClearAllBreakpoints ) ,
2021-10-12 21:21:22 -04:00
FCanExecuteAction ( ) // always allow
) ;
MenuBuilder . AddMenuEntry (
LOCTEXT ( " ClearBreakpoints " , " Remove all breakpoints " ) ,
LOCTEXT ( " ClearBreakpoints_ToolTip " , " Clear all breakpoints in this blueprint " ) ,
FSlateIcon ( ) ,
ClearAllBreakpoints ) ;
const bool bEnabledBreakpointExists = FKismetDebugUtilities : : FindBreakpointByPredicate (
Blueprint . Get ( ) ,
[ ] ( const FBlueprintBreakpoint & Breakpoint ) - > bool
{
return Breakpoint . IsEnabled ( ) ;
}
) ! = nullptr ;
if ( bEnabledBreakpointExists )
{
const FUIAction DisableAllBreakpoints (
2021-10-25 20:05:28 -04:00
FExecuteAction : : CreateSP ( this , & FBreakpointParentItem : : DisableAllBreakpoints ) ,
2021-10-12 21:21:22 -04:00
FCanExecuteAction ( ) // always allow
) ;
MenuBuilder . AddMenuEntry (
LOCTEXT ( " DisableBreakpoints " , " Disable all breakpoints " ) ,
LOCTEXT ( " DisableBreakpoints_ToolTip " , " Disable all breakpoints in this blueprint " ) ,
FSlateIcon ( ) ,
DisableAllBreakpoints ) ;
}
const bool bDisabledBreakpointExists = FKismetDebugUtilities : : FindBreakpointByPredicate (
Blueprint . Get ( ) ,
[ ] ( const FBlueprintBreakpoint & Breakpoint ) - > bool
{
return ! Breakpoint . IsEnabled ( ) ;
}
) ! = nullptr ;
if ( bDisabledBreakpointExists )
{
const FUIAction EnableAllBreakpoints (
2021-10-25 20:05:28 -04:00
FExecuteAction : : CreateSP ( this , & FBreakpointParentItem : : EnableAllBreakpoints ) ,
2021-10-12 21:21:22 -04:00
FCanExecuteAction ( ) // always allow
) ;
MenuBuilder . AddMenuEntry (
LOCTEXT ( " EnableBreakpoints " , " Enable all breakpoints " ) ,
LOCTEXT ( " EnableBreakpoints_ToolTip " , " Enable all breakpoints in this blueprint " ) ,
FSlateIcon ( ) ,
EnableAllBreakpoints ) ;
}
}
}
protected :
2021-11-07 23:43:01 -05:00
virtual void GatherChildren ( TArray < FDebugTreeItemPtr > & OutChildren , const FString & InSearchString , bool bRespectSearch ) override
{
// update search flags to match that of a root node
UpdateSearch ( InSearchString , FDebugLineItem : : SF_RootNode ) ;
if ( ! Blueprint . IsValid ( ) )
{
return ;
}
// Create children for each breakpoint
FKismetDebugUtilities : : ForeachBreakpoint (
Blueprint . Get ( ) ,
[ this , & OutChildren , & InSearchString , bRespectSearch ] ( FBlueprintBreakpoint & Breakpoint )
{
EnsureChildIsAdded ( OutChildren ,
FBreakpointLineItem ( Breakpoint . GetLocation ( ) , Blueprint . Get ( ) ) , InSearchString , bRespectSearch ) ;
}
) ;
// Make sure there is something there, to let the user know if there is nothing
if ( OutChildren . Num ( ) = = 0 )
{
EnsureChildIsAdded ( OutChildren ,
FMessageLineItem ( LOCTEXT ( " NoBreakpoints " , " No breakpoints " ) . ToString ( ) ) , InSearchString , bRespectSearch ) ;
}
}
2021-10-12 21:21:22 -04:00
virtual FText GetDisplayName ( ) const override
{
return LOCTEXT ( " Breakpoints " , " Breakpoints " ) ;
}
virtual FDebugLineItem * Duplicate ( ) const override
{
check ( false ) ;
return nullptr ;
}
2021-11-07 23:43:01 -05:00
virtual bool Compare ( const FDebugLineItem * BaseOther ) const override
{
check ( false ) ;
return false ;
}
2021-10-12 21:21:22 -04:00
virtual uint32 GetHash ( ) override
{
check ( false ) ;
return 0 ;
}
2021-10-25 20:05:28 -04:00
private :
void DisableAllBreakpoints ( ) const
{
FKismetDebugUtilities : : ForeachBreakpoint ( Blueprint . Get ( ) ,
[ ] ( FBlueprintBreakpoint & Breakpoint )
{
FKismetDebugUtilities : : SetBreakpointEnabled ( Breakpoint , false ) ;
}
) ;
}
void EnableAllBreakpoints ( ) const
{
FKismetDebugUtilities : : ForeachBreakpoint ( Blueprint . Get ( ) ,
[ ] ( FBlueprintBreakpoint & Breakpoint )
{
FKismetDebugUtilities : : SetBreakpointEnabled ( Breakpoint , true ) ;
}
) ;
}
void ClearAllBreakpoints ( ) const
{
FKismetDebugUtilities : : ClearBreakpoints ( Blueprint . Get ( ) ) ;
}
2021-10-12 21:21:22 -04:00
} ;
void FDebugLineItem : : SetBreakpointParentItemBlueprint ( FDebugTreeItemPtr InBreakpointParentItem , TWeakObjectPtr < UBlueprint > InBlueprint )
{
if ( ensureMsgf ( InBreakpointParentItem . IsValid ( ) & & InBreakpointParentItem - > Type = = DLT_BreakpointParent , TEXT ( " TreeItem is not Valid! " ) ) )
{
TSharedPtr < FBreakpointParentItem > BreakpointItem = StaticCastSharedPtr < FBreakpointParentItem > ( InBreakpointParentItem ) ;
BreakpointItem - > Blueprint = InBlueprint ;
}
}
//////////////////////////////////////////////////////////////////////////
// FParentLineItem
class FParentLineItem : public FLineItemWithChildren
{
protected :
// The parent object
TWeakObjectPtr < UObject > ObjectRef ;
public :
FParentLineItem ( UObject * Object )
: FLineItemWithChildren ( DLT_Parent )
{
ObjectRef = Object ;
}
2021-11-18 15:25:25 -05:00
virtual TSharedRef < SWidget > GenerateNameWidget ( TSharedPtr < FString > InSearchString ) override
{
return SNew ( PropertyInfoViewStyle : : STextHighlightOverlay )
. FullText ( this , & FParentLineItem : : GetDisplayName )
. HighlightText ( this , & FParentLineItem : : GetHighlightText , InSearchString )
[
SNew ( STextBlock )
. ToolTipText ( this , & FParentLineItem : : GetTooltipText )
. Text ( this , & FParentLineItem : : GetDisplayName )
] ;
}
2021-10-12 21:21:22 -04:00
virtual UObject * GetParentObject ( ) override
{
return ObjectRef . Get ( ) ;
}
virtual void GatherChildren ( TArray < FDebugTreeItemPtr > & OutChildren , const FString & InSearchString , bool bRespectSearch ) override
{
// update search flags to match that of a root node
UpdateSearch ( InSearchString , SF_RootNode ) ;
if ( UObject * ParentObject = ObjectRef . Get ( ) )
{
// every instance should have an automatic watch for 'self'
EnsureChildIsAdded ( OutChildren , FSelfWatchLineItem ( ParentObject ) , InSearchString , bRespectSearch ) ;
UBlueprint * ParentBP = FDebugLineItem : : GetBlueprintForObject ( ParentObject ) ;
if ( ParentBP ! = nullptr )
{
// Create children for each watch
if ( IsDebugLineTypeActive ( DLT_Watch ) )
{
2021-10-25 20:05:28 -04:00
FKismetDebugUtilities : : ForeachPinPropertyWatch ( ParentBP ,
[ this , & OutChildren , ParentObject , & InSearchString , bRespectSearch ] ( FBlueprintWatchedPin & WatchedPin )
2021-10-12 21:21:22 -04:00
{
EnsureChildIsAdded ( OutChildren ,
2021-10-25 20:05:28 -04:00
FWatchLineItem ( WatchedPin . Get ( ) , ParentObject , WatchedPin . GetPathToProperty ( ) ) , InSearchString , bRespectSearch ) ;
2021-10-12 21:21:22 -04:00
}
) ;
}
// It could also have active latent behaviors
if ( IsDebugLineTypeActive ( DLT_LatentAction ) )
{
if ( UWorld * World = GEngine - > GetWorldFromContextObject ( ParentObject , EGetWorldErrorMode : : ReturnNull ) )
{
FLatentActionManager & LatentActionManager = World - > GetLatentActionManager ( ) ;
// Get the current list of action UUIDs
TSet < int32 > UUIDSet ;
LatentActionManager . GetActiveUUIDs ( ParentObject , /*inout*/ UUIDSet ) ;
// Add the new ones
for ( TSet < int32 > : : TConstIterator RemainingIt ( UUIDSet ) ; RemainingIt ; + + RemainingIt )
{
const int32 UUID = * RemainingIt ;
EnsureChildIsAdded ( OutChildren ,
FLatentActionLineItem ( UUID , ParentObject ) , InSearchString , bRespectSearch ) ;
}
}
}
// Make sure there is something there, to let the user know if there is nothing
if ( OutChildren . Num ( ) = = 0 )
{
EnsureChildIsAdded ( OutChildren ,
FMessageLineItem ( LOCTEXT ( " NoDebugInfo " , " No debugging info " ) . ToString ( ) ) , InSearchString , bRespectSearch ) ;
}
}
//@TODO: try to get at TArray<struct FDebugDisplayProperty> DebugProperties in UGameViewportClient, if available
}
}
2021-11-07 23:43:01 -05:00
virtual TSharedRef < SWidget > GetNameIcon ( ) override
{
return SNew ( SImage )
. Image ( this , & FParentLineItem : : GetStatusImage )
. ColorAndOpacity_Raw ( this , & FParentLineItem : : GetStatusColor )
. ToolTipText ( this , & FParentLineItem : : GetStatusTooltip ) ;
}
2021-10-12 21:21:22 -04:00
const FSlateBrush * GetStatusImage ( ) const
{
if ( SKismetDebuggingView : : CurrentActiveObject = = ObjectRef )
{
2022-05-09 13:12:28 -04:00
return FAppStyle : : GetBrush ( TEXT ( " Kismet.Trace.CurrentIndex " ) ) ;
2021-10-12 21:21:22 -04:00
}
if ( ObjectRef . IsValid ( ) )
{
return FSlateIconFinder : : FindIconBrushForClass ( ObjectRef - > GetClass ( ) ) ;
}
2022-05-09 13:12:28 -04:00
return FAppStyle : : GetBrush ( TEXT ( " None " ) ) ;
2021-10-12 21:21:22 -04:00
}
FSlateColor GetStatusColor ( ) const
{
if ( SKismetDebuggingView : : CurrentActiveObject = = ObjectRef )
{
return FSlateColor ( EStyleColor : : AccentYellow ) ;
}
const UGraphEditorSettings * Settings = GetDefault < UGraphEditorSettings > ( ) ;
return Settings - > ObjectPinTypeColor ;
}
FText GetStatusTooltip ( ) const
{
if ( SKismetDebuggingView : : CurrentActiveObject = = ObjectRef )
{
return LOCTEXT ( " BreakpointHIt " , " Breakpoint Hit " ) ;
}
return FText : : GetEmpty ( ) ;
}
2021-11-07 23:43:01 -05:00
virtual void ExtendContextMenu ( class FMenuBuilder & MenuBuilder , bool bInDebuggerTab ) override
{
if ( UBlueprint * BP = Cast < UBlueprint > ( ObjectRef . Get ( ) ) )
{
if ( FKismetDebugUtilities : : BlueprintHasPinWatches ( BP ) )
{
FUIAction ClearAllWatches (
FExecuteAction : : CreateSP ( this , & FParentLineItem : : ClearAllWatches ) ,
FCanExecuteAction ( ) // always allow
) ;
MenuBuilder . AddMenuEntry (
LOCTEXT ( " ClearWatches " , " Clear all watches " ) ,
LOCTEXT ( " ClearWatches_ToolTip " , " Clear all watches in this blueprint " ) ,
FSlateIcon ( ) ,
ClearAllWatches ) ;
}
}
}
2021-10-12 21:21:22 -04:00
protected :
2021-11-07 23:43:01 -05:00
virtual FDebugLineItem * Duplicate ( ) const override
{
return new FParentLineItem ( ObjectRef . Get ( ) ) ;
}
2021-10-12 21:21:22 -04:00
virtual bool Compare ( const FDebugLineItem * BaseOther ) const override
{
FParentLineItem * Other = ( FParentLineItem * ) BaseOther ;
return ObjectRef . Get ( ) = = Other - > ObjectRef . Get ( ) ;
}
virtual uint32 GetHash ( ) override
{
return GetTypeHash ( ObjectRef ) ;
}
virtual FText GetDisplayName ( ) const override
{
UObject * Object = ObjectRef . Get ( ) ;
AActor * Actor = Cast < AActor > ( Object ) ;
if ( Actor ! = nullptr )
{
return FText : : FromString ( Actor - > GetActorLabel ( ) ) ;
}
else
{
return ( Object ! = nullptr ) ? FText : : FromString ( Object - > GetName ( ) ) : LOCTEXT ( " nullptr " , " (nullptr) " ) ;
}
}
2021-10-25 20:05:28 -04:00
private :
void ClearAllWatches ( ) const
{
if ( UBlueprint * Blueprint = Cast < UBlueprint > ( ObjectRef . Get ( ) ) )
{
FKismetDebugUtilities : : ClearPinWatches ( Blueprint ) ;
}
2021-10-12 21:21:22 -04:00
}
2021-11-18 15:25:25 -05:00
FText GetTooltipText ( ) const
{
if ( const UObject * Object = ObjectRef . Get ( ) )
{
if ( UWorld * World = Object - > GetTypedOuter < UWorld > ( ) )
{
2022-03-24 12:35:12 -04:00
FText WorldName = FText : : FromString ( GetDebugStringForWorld ( World ) ) ;
2021-11-18 15:25:25 -05:00
return FText : : FormatNamed ( LOCTEXT ( " ParentLineTooltip " , " {ObjectFullPath} \n World: {WorldFullPath} \n World Type: {WorldType} " ) ,
TEXT ( " ObjectFullPath " ) , FText : : FromString ( Object - > GetPathName ( ) ) ,
TEXT ( " WorldFullPath " ) , FText : : FromString ( World - > GetPathName ( ) ) ,
TEXT ( " WorldType " ) , WorldName ) ;
}
}
return GetDisplayName ( ) ;
}
2021-10-12 21:21:22 -04:00
} ;
//////////////////////////////////////////////////////////////////////////
// FTraceStackChildItem
class FTraceStackChildItem : public FDebugLineItem
{
protected :
int32 StackIndex ;
public :
FTraceStackChildItem ( int32 InStackIndex )
: FDebugLineItem ( DLT_TraceStackChild )
{
StackIndex = InStackIndex ;
}
virtual TSharedRef < SWidget > GenerateNameWidget ( TSharedPtr < FString > InSearchString ) override
{
return SNew ( PropertyInfoViewStyle : : STextHighlightOverlay )
. FullText ( this , & FTraceStackChildItem : : GetDisplayName )
. HighlightText ( this , & FTraceStackChildItem : : GetHighlightText , InSearchString )
[
SNew ( SHyperlink )
. Text ( this , & FTraceStackChildItem : : GetDisplayName )
2022-05-09 13:12:28 -04:00
. Style ( FAppStyle : : Get ( ) , " HoverOnlyHyperlink " )
2021-10-12 21:21:22 -04:00
. ToolTipText ( LOCTEXT ( " NavigateToDebugTraceLocationHyperlink_ToolTip " , " Navigate to the trace location " ) )
. OnNavigate ( this , & FTraceStackChildItem : : OnNavigateToNode )
] ;
}
// Visit time and actor name
virtual TSharedRef < SWidget > GenerateValueWidget ( TSharedPtr < FString > InSearchString ) override
{
return SNew ( PropertyInfoViewStyle : : STextHighlightOverlay )
. FullText ( this , & FTraceStackChildItem : : GetDescription )
. HighlightText ( this , & FTraceStackChildItem : : GetHighlightText , InSearchString )
[
SNew ( SHorizontalBox )
+ SHorizontalBox : : Slot ( )
. AutoWidth ( )
[
SNew ( SHyperlink )
. Text ( this , & FTraceStackChildItem : : GetContextObjectName )
2022-05-09 13:12:28 -04:00
. Style ( FAppStyle : : Get ( ) , " HoverOnlyHyperlink " )
2021-10-12 21:21:22 -04:00
. ToolTipText ( LOCTEXT ( " SelectActor_Tooltip " , " Select this actor " ) )
. OnNavigate ( this , & FTraceStackChildItem : : OnSelectContextObject )
]
+ SHorizontalBox : : Slot ( )
. AutoWidth ( )
[
SNew ( STextBlock )
. Text ( this , & FTraceStackChildItem : : GetVisitTime )
]
] ;
}
2021-11-07 23:43:01 -05:00
virtual TSharedRef < SWidget > GetNameIcon ( ) override
{
return SNew ( SImage )
2022-05-09 13:12:28 -04:00
. Image ( FAppStyle : : GetBrush (
2021-11-07 23:43:01 -05:00
( StackIndex > 0 ) ?
TEXT ( " Kismet.Trace.PreviousIndex " ) :
TEXT ( " Kismet.Trace.CurrentIndex " ) )
) ;
}
virtual FText GetDescription ( ) const override
{
return FText : : FromString ( GetContextObjectName ( ) . ToString ( ) + GetVisitTime ( ) . ToString ( ) ) ;
}
protected :
virtual FDebugLineItem * Duplicate ( ) const override
{
check ( false ) ;
return nullptr ;
}
virtual bool Compare ( const FDebugLineItem * BaseOther ) const override
{
check ( false ) ;
return false ;
}
virtual uint32 GetHash ( ) override
{
check ( false ) ;
return 0 ;
}
virtual FText GetDisplayName ( ) const override
{
UEdGraphNode * Node = GetNode ( ) ;
if ( Node ! = nullptr )
{
return Node - > GetNodeTitle ( ENodeTitleType : : ListView ) ;
}
else
{
return LOCTEXT ( " Unknown " , " (unknown) " ) ;
}
}
UEdGraphNode * GetNode ( ) const
{
const TSimpleRingBuffer < FKismetTraceSample > & TraceStack = FKismetDebugUtilities : : GetTraceStack ( ) ;
if ( StackIndex < TraceStack . Num ( ) )
{
const FKismetTraceSample & Sample = TraceStack ( StackIndex ) ;
UObject * ObjectContext = Sample . Context . Get ( ) ;
FString ContextName = ( ObjectContext ! = nullptr ) ? ObjectContext - > GetName ( ) : LOCTEXT ( " ObjectDoesNotExist " , " (object no longer exists) " ) . ToString ( ) ;
FString NodeName = TEXT ( " " ) ;
if ( ObjectContext ! = nullptr )
{
// Try to find the node that got executed
UEdGraphNode * Node = FKismetDebugUtilities : : FindSourceNodeForCodeLocation ( ObjectContext , Sample . Function . Get ( ) , Sample . Offset ) ;
return Node ;
}
}
return nullptr ;
}
2021-10-12 21:21:22 -04:00
FText GetVisitTime ( ) const
{
const TSimpleRingBuffer < FKismetTraceSample > & TraceStack = FKismetDebugUtilities : : GetTraceStack ( ) ;
if ( StackIndex < TraceStack . Num ( ) )
{
static const FNumberFormattingOptions TimeFormatOptions = FNumberFormattingOptions ( )
. SetMinimumFractionalDigits ( 2 )
. SetMaximumFractionalDigits ( 2 ) ;
return FText : : Format ( LOCTEXT ( " VisitTimeFmt " , " @ {0} s " ) , FText : : AsNumber ( TraceStack ( StackIndex ) . ObservationTime - GStartTime , & TimeFormatOptions ) ) ;
}
return FText : : GetEmpty ( ) ;
}
FText GetContextObjectName ( ) const
{
const TSimpleRingBuffer < FKismetTraceSample > & TraceStack = FKismetDebugUtilities : : GetTraceStack ( ) ;
UObject * ObjectContext = ( StackIndex < TraceStack . Num ( ) ) ? TraceStack ( StackIndex ) . Context . Get ( ) : nullptr ;
return ( ObjectContext ! = nullptr ) ? FText : : FromString ( ObjectContext - > GetName ( ) ) : LOCTEXT ( " ObjectDoesNotExist " , " (object no longer exists) " ) ;
}
void OnNavigateToNode ( )
{
if ( UEdGraphNode * Node = GetNode ( ) )
{
FKismetEditorUtilities : : BringKismetToFocusAttentionOnObject ( Node ) ;
}
}
void OnSelectContextObject ( )
{
const TSimpleRingBuffer < FKismetTraceSample > & TraceStack = FKismetDebugUtilities : : GetTraceStack ( ) ;
UObject * ObjectContext = ( StackIndex < TraceStack . Num ( ) ) ? TraceStack ( StackIndex ) . Context . Get ( ) : nullptr ;
// Add the object to the selection set
if ( AActor * Actor = Cast < AActor > ( ObjectContext ) )
{
GEditor - > SelectActor ( Actor , true , true , true ) ;
}
else
{
UE_LOG ( LogBlueprintDebugTreeView , Warning , TEXT ( " Cannot select the non-actor object '%s' " ) , ( ObjectContext ! = nullptr ) ? * ObjectContext - > GetName ( ) : TEXT ( " (nullptr) " ) ) ;
}
}
} ;
//////////////////////////////////////////////////////////////////////////
// FTraceStackParentItem
class FTraceStackParentItem : public FLineItemWithChildren
{
public :
FTraceStackParentItem ( )
: FLineItemWithChildren ( DLT_TraceStackParent )
{
}
virtual bool HasChildren ( ) const override
{
return ! ChildrenMirrorsArr . IsEmpty ( ) ;
}
2021-11-07 23:43:01 -05:00
protected :
virtual FDebugLineItem * Duplicate ( ) const override
{
check ( false ) ;
return nullptr ;
}
virtual bool Compare ( const FDebugLineItem * BaseOther ) const override
{
check ( false ) ;
return false ;
}
virtual uint32 GetHash ( ) override
{
check ( false ) ;
return 0 ;
}
virtual FText GetDisplayName ( ) const override
{
return LOCTEXT ( " ExecutionTrace " , " Execution Trace " ) ;
}
2021-10-12 21:21:22 -04:00
virtual void GatherChildren ( TArray < FDebugTreeItemPtr > & OutChildren , const FString & InSearchString , bool bRespectSearch ) override
{
// update search flags to match that of a root node
UpdateSearch ( InSearchString , SF_RootNode ) ;
const TSimpleRingBuffer < FKismetTraceSample > & TraceStack = FKismetDebugUtilities : : GetTraceStack ( ) ;
const int32 NumVisible = TraceStack . Num ( ) ;
// Create any new stack entries that are needed
for ( int32 i = ChildrenMirrorsArr . Num ( ) ; i < NumVisible ; + + i )
{
ChildrenMirrorsArr . Add ( MakeShareable ( new FTraceStackChildItem ( i ) ) ) ;
}
// Add the visible stack entries as children
for ( int32 i = 0 ; i < NumVisible ; + + i )
{
OutChildren . Add ( ChildrenMirrorsArr [ i ] ) ;
}
}
// use an array to store children mirrors instead of a set so it's ordered
TArray < FDebugTreeItemPtr > ChildrenMirrorsArr ;
} ;
//////////////////////////////////////////////////////////////////////////
// SDebugLineItem
class SDebugLineItem : public SMultiColumnTableRow < FDebugTreeItemPtr >
{
protected :
FDebugTreeItemPtr ItemToEdit ;
TSharedPtr < FString > SearchString ;
public :
SLATE_BEGIN_ARGS ( SDebugLineItem ) { }
SLATE_END_ARGS ( )
virtual TSharedRef < SWidget > GenerateWidgetForColumn ( const FName & ColumnName ) override
{
TSharedPtr < SWidget > ColumnContent = nullptr ;
if ( ColumnName = = SKismetDebugTreeView : : ColumnId_Name )
{
SAssignNew ( ColumnContent , SHorizontalBox )
+ SHorizontalBox : : Slot ( )
. HAlign ( HAlign_Left )
. VAlign ( VAlign_Fill )
. AutoWidth ( )
[
SNew ( PropertyInfoViewStyle : : SIndent , SharedThis ( this ) )
]
+ SHorizontalBox : : Slot ( )
. HAlign ( HAlign_Left )
. VAlign ( VAlign_Center )
. AutoWidth ( )
[
SNew ( PropertyInfoViewStyle : : SExpanderArrow , SharedThis ( this ) )
. HasChildren_Lambda ( [ ItemToEdit = ItemToEdit ] ( )
{
const bool HasChildren = ItemToEdit - > HasChildren ( ) ;
return HasChildren ;
} )
]
+ SHorizontalBox : : Slot ( )
. AutoWidth ( )
. HAlign ( HAlign_Left )
. VAlign ( VAlign_Center )
[
ItemToEdit - > GetNameIcon ( )
]
+ SHorizontalBox : : Slot ( )
. AutoWidth ( )
. HAlign ( HAlign_Left )
. VAlign ( VAlign_Center )
. Padding ( 5.f , 0.f , 0.f , 0.f )
[
ItemToEdit - > GenerateNameWidget ( SearchString )
] ;
}
else if ( ColumnName = = SKismetDebugTreeView : : ColumnId_Value )
{
SAssignNew ( ColumnContent , SHorizontalBox )
+ SHorizontalBox : : Slot ( )
. AutoWidth ( )
[
ItemToEdit - > GetValueIcon ( )
]
+ SHorizontalBox : : Slot ( )
. AutoWidth ( )
. HAlign ( HAlign_Left )
. Padding ( .5f , 1.f )
[
ItemToEdit - > GenerateValueWidget ( SearchString )
] ;
}
else
{
SAssignNew ( ColumnContent , STextBlock )
. Text ( LOCTEXT ( " Error " , " Error " ) ) ;
}
return SNew ( SBox )
. Padding ( FMargin ( 0.5f , 0.5f ) )
[
SNew ( SBorder )
. BorderImage ( FAppStyle : : Get ( ) . GetBrush ( " DetailsView.CategoryMiddle " ) )
. BorderBackgroundColor_Static (
PropertyInfoViewStyle : : GetRowBackgroundColor ,
static_cast < ITableRow * > ( this )
)
[
ColumnContent . ToSharedRef ( )
]
] ;
}
void Construct ( const FArguments & InArgs , TSharedRef < STableViewBase > OwnerTableView , FDebugTreeItemPtr InItemToEdit , TSharedPtr < FString > InSearchString )
{
ItemToEdit = InItemToEdit ;
SearchString = InSearchString ;
SMultiColumnTableRow < FDebugTreeItemPtr > : : Construct ( FSuperRowType : : FArguments ( ) , OwnerTableView ) ;
}
protected :
virtual FVector2D ComputeDesiredSize ( float LayoutScaleMultiplier ) const override
{
const TSharedRef < SWidget > * NameWidget = GetWidgetFromColumnId ( SKismetDebugTreeView : : ColumnId_Name ) ;
const TSharedRef < SWidget > * ValWidget = GetWidgetFromColumnId ( SKismetDebugTreeView : : ColumnId_Value ) ;
if ( NameWidget & & ValWidget )
{
return FMath : : Max ( ( * NameWidget ) - > GetDesiredSize ( ) , ( * ValWidget ) - > GetDesiredSize ( ) ) * FVector2D ( 2.0f , 1.0f ) ;
}
return STableRow < FDebugTreeItemPtr > : : ComputeDesiredSize ( LayoutScaleMultiplier ) ;
}
} ;
//////////////////////////////////////////////////////////////////////////
// SKismetDebugTreeView
void SKismetDebugTreeView : : Construct ( const FArguments & InArgs )
{
bFilteredItemsDirty = false ;
2022-01-03 18:14:37 -05:00
bInDebuggerTab = InArgs . _InDebuggerTab ;
2021-10-12 21:21:22 -04:00
SearchString = MakeShared < FString > ( ) ;
2022-01-18 16:46:05 -05:00
SearchMessageItem = MakeMessageItem ( LOCTEXT ( " NoItemsMatchSearch " , " No entries match the search text " ) . ToString ( ) ) ;
2021-10-12 21:21:22 -04:00
ChildSlot
[
SAssignNew ( TreeView , STreeView < FDebugTreeItemPtr > )
. TreeItemsSource ( & FilteredTreeRoots )
. SelectionMode ( InArgs . _SelectionMode )
. OnGetChildren ( this , & SKismetDebugTreeView : : OnGetChildren )
. OnGenerateRow ( this , & SKismetDebugTreeView : : OnGenerateRow )
. OnExpansionChanged ( InArgs . _OnExpansionChanged )
2021-10-25 20:05:28 -04:00
. OnContextMenuOpening ( this , & SKismetDebugTreeView : : OnMakeContextMenu )
2021-10-12 21:21:22 -04:00
. TreeViewStyle ( & FAppStyle : : Get ( ) . GetWidgetStyle < FTableViewStyle > ( " PropertyTable.InViewport.ListView " ) )
. HeaderRow ( InArgs . _HeaderRow )
] ;
}
void SKismetDebugTreeView : : Tick ( const FGeometry & AllottedGeometry , const double InCurrentTime , const float InDeltaTime )
{
if ( bFilteredItemsDirty )
{
UpdateFilteredItems ( ) ;
bFilteredItemsDirty = false ;
}
}
void SKismetDebugTreeView : : AddTreeItemUnique ( const FDebugTreeItemPtr & Item )
{
RootTreeItems . AddUnique ( Item ) ;
RequestUpdateFilteredItems ( ) ;
}
bool SKismetDebugTreeView : : RemoveTreeItem ( const FDebugTreeItemPtr & Item )
{
if ( RootTreeItems . Remove ( Item ) ! = 0 )
{
RequestUpdateFilteredItems ( ) ;
return true ;
}
return false ;
}
void SKismetDebugTreeView : : ClearTreeItems ( )
{
if ( ! RootTreeItems . IsEmpty ( ) )
{
RootTreeItems . Empty ( ) ;
RequestUpdateFilteredItems ( ) ;
}
}
void SKismetDebugTreeView : : SetSearchText ( const FText & InSearchText )
{
* SearchString = InSearchText . ToString ( ) ;
RequestUpdateFilteredItems ( ) ;
}
void SKismetDebugTreeView : : RequestUpdateFilteredItems ( )
{
bFilteredItemsDirty = true ;
}
const TArray < FDebugTreeItemPtr > & SKismetDebugTreeView : : GetRootTreeItems ( ) const
{
return RootTreeItems ;
}
int32 SKismetDebugTreeView : : GetSelectedItems ( TArray < FDebugTreeItemPtr > & OutItems )
{
return TreeView - > GetSelectedItems ( OutItems ) ;
}
void SKismetDebugTreeView : : ClearExpandedItems ( )
{
TreeView - > ClearExpandedItems ( ) ;
}
bool SKismetDebugTreeView : : IsScrolling ( ) const
{
return TreeView - > IsScrolling ( ) ;
}
void SKismetDebugTreeView : : SetItemExpansion ( FDebugTreeItemPtr InItem , bool bInShouldExpandItem )
{
TreeView - > SetItemExpansion ( InItem , bInShouldExpandItem ) ;
}
void SKismetDebugTreeView : : UpdateFilteredItems ( )
{
FilteredTreeRoots . Empty ( ) ;
for ( FDebugTreeItemPtr Item : RootTreeItems )
{
if ( Item . IsValid ( ) )
{
if ( Item - > CanHaveChildren ( ) )
{
FLineItemWithChildren * ItemWithChildren = StaticCast < FLineItemWithChildren * > ( Item . Get ( ) ) ;
if ( SearchString - > IsEmpty ( ) | | ItemWithChildren - > SearchRecursive ( * SearchString , TreeView ) )
{
FilteredTreeRoots . Add ( Item ) ;
}
}
else
{
Item - > UpdateSearch ( * SearchString , FDebugLineItem : : SF_RootNode ) ;
if ( SearchString - > IsEmpty ( ) | | Item - > IsVisible ( ) )
{
FilteredTreeRoots . Add ( Item ) ;
}
}
}
}
2022-01-18 16:46:05 -05:00
if ( FilteredTreeRoots . IsEmpty ( ) )
{
FilteredTreeRoots . Add ( SearchMessageItem ) ;
}
2021-10-12 21:21:22 -04:00
TreeView - > RequestTreeRefresh ( ) ;
}
TSharedRef < ITableRow > SKismetDebugTreeView : : OnGenerateRow ( FDebugTreeItemPtr InItem , const TSharedRef < STableViewBase > & OwnerTable )
{
return SNew ( SDebugLineItem , OwnerTable , InItem , SearchString ) ;
}
void SKismetDebugTreeView : : OnGetChildren ( FDebugTreeItemPtr InParent , TArray < FDebugTreeItemPtr > & OutChildren )
{
InParent - > GatherChildrenBase ( OutChildren , * SearchString ) ;
}
2021-10-25 20:05:28 -04:00
TSharedPtr < SWidget > SKismetDebugTreeView : : OnMakeContextMenu ( ) const
{
FMenuBuilder MenuBuilder ( true , nullptr ) ;
MenuBuilder . BeginSection ( " DebugActions " , LOCTEXT ( " DebugActionsMenuHeading " , " Debug Actions " ) ) ;
{
TArray < FDebugTreeItemPtr > SelectedItems ;
TreeView - > GetSelectedItems ( SelectedItems ) ;
for ( FDebugTreeItemPtr & Item : SelectedItems )
{
2021-11-07 23:43:01 -05:00
Item - > MakeMenu ( MenuBuilder , bInDebuggerTab ) ;
2021-10-25 20:05:28 -04:00
}
}
MenuBuilder . EndSection ( ) ;
return MenuBuilder . MakeWidget ( ) ;
}
2021-10-12 21:21:22 -04:00
FDebugTreeItemPtr SKismetDebugTreeView : : MakeTraceStackParentItem ( )
{
return MakeShared < FTraceStackParentItem > ( ) ;
}
FDebugTreeItemPtr SKismetDebugTreeView : : MakeBreakpointParentItem ( TWeakObjectPtr < UBlueprint > InBlueprint )
{
return MakeShared < FBreakpointParentItem > ( InBlueprint ) ;
}
FDebugTreeItemPtr SKismetDebugTreeView : : MakeMessageItem ( const FString & InMessage )
{
return MakeShared < FMessageLineItem > ( InMessage ) ;
}
FDebugTreeItemPtr SKismetDebugTreeView : : MakeParentItem ( UObject * InObject )
{
return MakeShared < FParentLineItem > ( InObject ) ;
}
2021-10-25 20:05:28 -04:00
FDebugTreeItemPtr SKismetDebugTreeView : : MakeWatchLineItem ( const UEdGraphPin * InPinRef , UObject * InDebugObject )
2021-10-12 21:21:22 -04:00
{
2021-10-25 20:05:28 -04:00
return MakeShared < FWatchLineItem > ( InPinRef , InDebugObject ) ;
2021-10-12 21:21:22 -04:00
}
# undef LOCTEXT_NAMESPACE