2021-09-28 13:33:17 -04:00
// Copyright Epic Games, Inc. All Rights Reserved.
# include "SStateTreeViewRow.h"
# include "SStateTreeView.h"
2024-08-01 05:38:41 -04:00
# include "SStateTreeExpanderArrow.h"
2023-06-20 13:49:25 -04:00
# include "StateTreeEditor.h"
2023-06-15 11:38:28 -04:00
# include "StateTreeEditorData.h"
2021-09-28 13:33:17 -04:00
# include "StateTreeEditorStyle.h"
# include "Widgets/Text/SInlineEditableTextBlock.h"
# include "Widgets/Layout/SScrollBox.h"
2023-06-15 11:38:28 -04:00
# include "Widgets/Layout/SSpacer.h"
2023-12-05 17:55:30 -05:00
# include "StateTree.h"
2024-08-01 05:38:41 -04:00
# include "StateTreeConditionBase.h"
# include "StateTreeDescriptionHelpers.h"
# include "StateTreeDragDrop.h"
2024-08-13 09:09:54 -04:00
# include "StateTreeEditorModule.h"
2021-09-28 13:33:17 -04:00
# include "StateTreeState.h"
2022-02-03 09:13:49 -05:00
# include "StateTreeTaskBase.h"
2021-09-28 13:33:17 -04:00
# include "StateTreeViewModel.h"
2023-01-19 00:48:07 -05:00
# include "Widgets/Views/SListView.h"
2024-04-05 03:37:02 -04:00
# include "TextStyleDecorator.h"
2024-04-17 03:01:36 -04:00
# include "Customizations/StateTreeEditorNodeUtils.h"
2024-08-01 05:38:41 -04:00
# include "Widgets/Layout/SWrapBox.h"
2024-04-05 03:37:02 -04:00
# include "Widgets/Text/SRichTextBlock.h"
2024-08-01 05:38:41 -04:00
# include "Widgets/Input/SButton.h"
2021-09-28 13:33:17 -04:00
# define LOCTEXT_NAMESPACE "StateTreeEditor"
2023-09-26 11:50:26 -04:00
namespace UE : : StateTree : : Editor
{
FLinearColor LerpColorSRGB ( const FLinearColor ColorA , FLinearColor ColorB , float T )
{
const FColor A = ColorA . ToFColorSRGB ( ) ;
const FColor B = ColorB . ToFColorSRGB ( ) ;
return FLinearColor ( FColor (
static_cast < uint8 > ( FMath : : RoundToInt ( static_cast < float > ( A . R ) * ( 1.f - T ) + static_cast < float > ( B . R ) * T ) ) ,
static_cast < uint8 > ( FMath : : RoundToInt ( static_cast < float > ( A . G ) * ( 1.f - T ) + static_cast < float > ( B . G ) * T ) ) ,
static_cast < uint8 > ( FMath : : RoundToInt ( static_cast < float > ( A . B ) * ( 1.f - T ) + static_cast < float > ( B . B ) * T ) ) ,
static_cast < uint8 > ( FMath : : RoundToInt ( static_cast < float > ( A . A ) * ( 1.f - T ) + static_cast < float > ( B . A ) * T ) ) ) ) ;
}
} // UE:StateTree::Editor
2023-12-14 02:55:56 -05:00
void SStateTreeViewRow : : Construct ( const FArguments & InArgs , const TSharedRef < STableViewBase > & InOwnerTableView , TWeakObjectPtr < UStateTreeState > InState , const TSharedPtr < SScrollBox > & ViewBox , TSharedPtr < FStateTreeViewModel > InStateTreeViewModel )
2021-09-28 13:33:17 -04:00
{
StateTreeViewModel = InStateTreeViewModel ;
WeakState = InState ;
2023-06-15 11:38:28 -04:00
const UStateTreeState * State = InState . Get ( ) ;
2024-04-05 03:37:02 -04:00
WeakEditorData = State ! = nullptr ? State - > GetTypedOuter < UStateTreeEditorData > ( ) : nullptr ;
2021-09-28 13:33:17 -04:00
2023-06-05 13:12:19 -04:00
ConstructInternal ( STableRow : : FArguments ( )
2023-03-14 13:35:46 -04:00
. OnDragDetected ( this , & SStateTreeViewRow : : HandleDragDetected )
2024-08-01 05:38:41 -04:00
. OnDragLeave ( this , & SStateTreeViewRow : : HandleDragLeave )
2023-03-14 13:35:46 -04:00
. OnCanAcceptDrop ( this , & SStateTreeViewRow : : HandleCanAcceptDrop )
. OnAcceptDrop ( this , & SStateTreeViewRow : : HandleAcceptDrop )
. Style ( & FStateTreeEditorStyle : : Get ( ) . GetWidgetStyle < FTableRowStyle > ( " StateTree.Selection " ) )
, InOwnerTableView ) ;
2021-09-28 13:33:17 -04:00
2023-06-05 13:12:19 -04:00
static constexpr FLinearColor IconTint = FLinearColor ( 1 , 1 , 1 , 0.5f ) ;
2022-06-30 03:06:38 -04:00
2024-08-01 05:38:41 -04:00
const float ExpanderArrowTopPadding = FMath : : FloorToFloat ( ( UE : : StateTree : : Editor : : StateRowHeight - 16.f ) / 2.f ) ;
auto MakeTransitionWidget = [ this ] ( const EStateTreeTransitionTrigger Trigger , const FSlateBrush * Icon )
{
FTransitionDescFilterOptions FilterOptions ;
FilterOptions . bUseMask = EnumHasAnyFlags ( Trigger , EStateTreeTransitionTrigger : : OnTick | EStateTreeTransitionTrigger : : OnEvent ) ;
return SNew ( SBox )
. HeightOverride ( UE : : StateTree : : Editor : : StateRowHeight )
. Visibility ( this , & SStateTreeViewRow : : GetTransitionsVisibility , Trigger )
[
SNew ( SHorizontalBox )
+ SHorizontalBox : : Slot ( )
. VAlign ( VAlign_Center )
. AutoWidth ( )
. Padding ( FMargin ( 0.f , 0.f , 0.f , 0.f ) )
[
SNew ( SHorizontalBox )
+ SHorizontalBox : : Slot ( )
. VAlign ( VAlign_Center )
. AutoWidth ( )
[
SNew ( SImage )
. Image ( Icon )
]
+ SHorizontalBox : : Slot ( )
. VAlign ( VAlign_Center )
. AutoWidth ( )
[
SNew ( SImage )
. Image ( this , & SStateTreeViewRow : : GetTransitionsIcon , Trigger )
. ColorAndOpacity ( IconTint )
]
]
+ SHorizontalBox : : Slot ( )
. VAlign ( VAlign_Center )
. AutoWidth ( )
. Padding ( FMargin ( 4.f , 0.f , 12.f , 0.f ) )
[
SNew ( SOverlay )
+ SOverlay : : Slot ( )
[
MakeTransitionWidgets ( Trigger , FilterOptions )
]
+ SOverlay : : Slot ( )
[
// Breakpoint box
SNew ( SHorizontalBox )
+ SHorizontalBox : : Slot ( )
. VAlign ( VAlign_Top )
. HAlign ( HAlign_Left )
. AutoWidth ( )
[
SNew ( SBox )
. Padding ( FMargin ( - 4.f , - 4.f , 0.f , 0.f ) )
[
SNew ( SImage )
. DesiredSizeOverride ( FVector2D ( 10.f , 10.f ) )
. Image ( FStateTreeEditorStyle : : Get ( ) . GetBrush ( TEXT ( " StateTreeEditor.Debugger.Breakpoint.EnabledAndValid " ) ) )
. Visibility ( this , & SStateTreeViewRow : : GetTransitionsBreakpointVisibility , Trigger )
. ToolTipText_Lambda ( [ this , Trigger , InFilterOptions = FilterOptions ]
{
FTransitionDescFilterOptions FilterOptions = InFilterOptions ;
FilterOptions . WithBreakpoint = ETransitionDescRequirement : : RequiredTrue ;
return FText : : Format ( LOCTEXT ( " TransitionBreakpointTooltip " , " Break when executing transition: {0} " ) ,
GetTransitionsDesc ( Trigger , FilterOptions ) ) ;
} )
]
]
]
]
] ;
} ;
2021-09-28 13:33:17 -04:00
this - > ChildSlot
2022-10-31 15:13:40 -04:00
. HAlign ( HAlign_Fill )
[
SNew ( SBox )
2023-05-08 13:32:14 -04:00
. MinDesiredWidth_Lambda ( [ WeakOwnerViewBox = ViewBox . ToWeakPtr ( ) ] ( )
2023-03-14 13:35:46 -04:00
{
2023-05-08 13:32:14 -04:00
// Captured as weak ptr so we don't prevent our parent widget from being destroyed (circular pointer reference).
if ( const TSharedPtr < SScrollBox > OwnerViewBox = WeakOwnerViewBox . Pin ( ) )
{
// Make the row at least as wide as the view.
// The -1 is needed or we'll see a scrollbar.
return OwnerViewBox - > GetTickSpaceGeometry ( ) . GetLocalSize ( ) . X - 1 ;
}
return 0.f ;
2023-03-14 13:35:46 -04:00
} )
2024-08-01 05:38:41 -04:00
. Padding ( FMargin ( 0 , 0 , 0 , 0 ) )
2022-06-30 03:06:38 -04:00
[
2022-10-31 15:13:40 -04:00
SNew ( SHorizontalBox )
+ SHorizontalBox : : Slot ( )
. VAlign ( VAlign_Fill )
. HAlign ( HAlign_Left )
. AutoWidth ( )
[
2024-08-01 05:38:41 -04:00
SNew ( SStateTreeExpanderArrow , SharedThis ( this ) )
. IndentAmount ( 24.f )
2022-10-31 15:13:40 -04:00
. BaseIndentLevel ( 0 )
2024-08-01 05:38:41 -04:00
. ImageSize ( FVector2f ( 16 , 16 ) )
. ImagePadding ( FMargin ( 9 , 14 , 0 , 0 ) )
. Image ( this , & SStateTreeViewRow : : GetSelectorIcon )
. ColorAndOpacity ( FLinearColor ( 1 , 1 , 1 , 0.2f ) )
. WireColorAndOpacity ( FLinearColor ( 1 , 1 , 1 , 0.2f ) )
2022-10-31 15:13:40 -04:00
]
2021-09-28 13:33:17 -04:00
2022-10-31 15:13:40 -04:00
+ SHorizontalBox : : Slot ( )
2023-03-14 13:35:46 -04:00
. VAlign ( VAlign_Fill )
. HAlign ( HAlign_Left )
2022-10-31 15:13:40 -04:00
. AutoWidth ( )
2024-08-01 05:38:41 -04:00
. Padding ( FMargin ( 0 , 6 , 0 , 6 ) )
2022-10-31 15:13:40 -04:00
[
2024-08-01 05:38:41 -04:00
// State and tasks
SNew ( SVerticalBox )
+ SVerticalBox : : Slot ( )
. AutoHeight ( )
2022-10-31 15:13:40 -04:00
[
2024-08-01 05:38:41 -04:00
// State
SNew ( SBox )
. HeightOverride ( UE : : StateTree : : Editor : : StateRowHeight )
. HAlign ( HAlign_Left )
2022-10-31 15:13:40 -04:00
[
SNew ( SHorizontalBox )
2023-04-12 07:59:16 -04:00
// State Box
2022-10-31 15:13:40 -04:00
+ SHorizontalBox : : Slot ( )
. VAlign ( VAlign_Center )
2024-08-01 05:38:41 -04:00
//.FillWidth(1.f)
2022-10-31 15:13:40 -04:00
. AutoWidth ( )
[
SNew ( SBox )
2024-08-01 05:38:41 -04:00
. HeightOverride ( UE : : StateTree : : Editor : : StateRowHeight )
2023-03-14 13:35:46 -04:00
. VAlign ( VAlign_Fill )
2022-10-31 15:13:40 -04:00
[
2023-03-14 13:35:46 -04:00
SNew ( SBorder )
2024-08-01 05:38:41 -04:00
. BorderImage ( FStateTreeEditorStyle : : Get ( ) . GetBrush ( " StateTree.State.Border " ) )
. BorderBackgroundColor ( this , & SStateTreeViewRow : : GetActiveStateColor )
[
SNew ( SBorder )
. BorderImage ( FStateTreeEditorStyle : : Get ( ) . GetBrush ( " StateTree.State " ) )
. BorderBackgroundColor ( this , & SStateTreeViewRow : : GetTitleColor , 1.0f , 0.0f )
. Padding ( FMargin ( 0.f , 0.f , 12.f , 0.f ) )
. IsEnabled_Lambda ( [ InState ]
2023-06-05 13:12:19 -04:00
{
const UStateTreeState * State = InState . Get ( ) ;
return State ! = nullptr & & State - > bEnabled ;
} )
2023-03-14 13:35:46 -04:00
[
2024-08-01 05:38:41 -04:00
SNew ( SOverlay )
+ SOverlay : : Slot ( )
2024-04-12 07:21:04 -04:00
[
2024-08-01 05:38:41 -04:00
SNew ( SHorizontalBox )
// Sub tree marker
+ SHorizontalBox : : Slot ( )
. VAlign ( VAlign_Center )
. AutoWidth ( )
. Padding ( FMargin ( 0 , 0 , 0 , 0 ) )
2024-04-12 07:21:04 -04:00
[
2024-08-01 05:38:41 -04:00
SNew ( SBox )
. WidthOverride ( 4.f )
. HeightOverride ( UE : : StateTree : : Editor : : StateRowHeight )
. Visibility ( this , & SStateTreeViewRow : : GetSubTreeVisibility )
. VAlign ( VAlign_Fill )
. HAlign ( HAlign_Fill )
[
SNew ( SBorder )
. BorderImage ( FAppStyle : : GetBrush ( " WhiteBrush " ) )
. BorderBackgroundColor ( FLinearColor ( 1 , 1 , 1 , 0.25f ) )
]
2024-04-12 07:21:04 -04:00
]
2024-08-01 05:38:41 -04:00
// Conditions icon
+ SHorizontalBox : : Slot ( )
. VAlign ( VAlign_Center )
. AutoWidth ( )
2023-06-15 11:38:28 -04:00
[
2024-08-01 05:38:41 -04:00
SNew ( SBox )
. Padding ( FMargin ( 4.f , 0.f , - 4.f , 0.f ) )
. Visibility ( this , & SStateTreeViewRow : : GetConditionVisibility )
[
SNew ( SImage )
. ColorAndOpacity ( IconTint )
. Image ( FStateTreeEditorStyle : : Get ( ) . GetBrush ( " StateTreeEditor.StateConditions " ) )
. ToolTipText ( LOCTEXT ( " StateHasEnterConditions " , " State selection is guarded with enter conditions. " ) )
]
2023-06-15 11:38:28 -04:00
]
2024-08-01 05:38:41 -04:00
// Selector icon
+ SHorizontalBox : : Slot ( )
. VAlign ( VAlign_Center )
. AutoWidth ( )
2023-06-15 11:38:28 -04:00
[
2024-08-01 05:38:41 -04:00
SNew ( SBox )
. Padding ( FMargin ( 4.f , 0.f , 0.f , 0.f ) )
[
SNew ( SImage )
. Image ( this , & SStateTreeViewRow : : GetSelectorIcon )
. ColorAndOpacity ( IconTint )
. ToolTipText ( this , & SStateTreeViewRow : : GetSelectorTooltip )
]
2023-06-15 11:38:28 -04:00
]
2024-08-01 05:38:41 -04:00
// Warnings
+ SHorizontalBox : : Slot ( )
. VAlign ( VAlign_Center )
. AutoWidth ( )
[
SNew ( SBox )
. Padding ( FMargin ( 2.f , 0.f , 2.f , 1.f ) )
. Visibility ( this , & SStateTreeViewRow : : GetWarningsVisibility )
[
SNew ( SImage )
. Image ( FAppStyle : : Get ( ) . GetBrush ( " Icons.Warning " ) )
. ToolTipText ( this , & SStateTreeViewRow : : GetWarningsTooltipText )
]
]
// State Name
+ SHorizontalBox : : Slot ( )
. VAlign ( VAlign_Center )
. AutoWidth ( )
[
SAssignNew ( NameTextBlock , SInlineEditableTextBlock )
. Style ( FStateTreeEditorStyle : : Get ( ) , " StateTree.State.TitleInlineEditableText " )
. OnVerifyTextChanged_Lambda ( [ ] ( const FText & NewLabel , FText & OutErrorMessage )
{
return ! NewLabel . IsEmptyOrWhitespace ( ) ;
} )
. OnTextCommitted ( this , & SStateTreeViewRow : : HandleNodeLabelTextCommitted )
. Text ( this , & SStateTreeViewRow : : GetStateDesc )
. ToolTipText ( this , & SStateTreeViewRow : : GetStateTypeTooltip )
. Clipping ( EWidgetClipping : : ClipToBounds )
. IsSelected ( this , & SStateTreeViewRow : : IsStateSelected )
]
// Linked State
+ SHorizontalBox : : Slot ( )
. VAlign ( VAlign_Center )
. AutoWidth ( )
[
SNew ( SBox )
. HeightOverride ( UE : : StateTree : : Editor : : StateRowHeight )
. VAlign ( VAlign_Fill )
. Visibility ( this , & SStateTreeViewRow : : GetLinkedStateVisibility )
[
// Link icon
SNew ( SHorizontalBox )
+ SHorizontalBox : : Slot ( )
. VAlign ( VAlign_Center )
. AutoWidth ( )
. Padding ( FMargin ( 4.f , 0.f , 4.f , 0.f ) )
[
SNew ( SImage )
. ColorAndOpacity ( IconTint )
. Image ( FStateTreeEditorStyle : : Get ( ) . GetBrush ( " StateTreeEditor.StateLinked " ) )
]
// Linked State
+ SHorizontalBox : : Slot ( )
. VAlign ( VAlign_Center )
. AutoWidth ( )
[
SNew ( STextBlock )
. Text ( this , & SStateTreeViewRow : : GetLinkedStateDesc )
. TextStyle ( FStateTreeEditorStyle : : Get ( ) , " StateTree.Details " )
]
]
]
// State ID
+ SHorizontalBox : : Slot ( )
. VAlign ( VAlign_Center )
. AutoWidth ( )
[
SNew ( STextBlock )
. Visibility_Lambda ( [ ] ( )
2023-06-15 11:38:28 -04:00
{
2024-08-01 05:38:41 -04:00
return UE : : StateTree : : Editor : : GbDisplayItemIds ? EVisibility : : Visible : EVisibility : : Collapsed ;
2023-06-15 11:38:28 -04:00
} )
2024-08-01 05:38:41 -04:00
. Text ( this , & SStateTreeViewRow : : GetStateIDDesc )
. TextStyle ( FStateTreeEditorStyle : : Get ( ) , " StateTree.Details " )
]
2023-03-14 13:35:46 -04:00
]
2024-08-01 05:38:41 -04:00
+ SOverlay : : Slot ( )
2023-06-21 10:32:41 -04:00
[
2024-08-01 05:38:41 -04:00
SNew ( SHorizontalBox )
2023-06-15 11:38:28 -04:00
2024-08-01 05:38:41 -04:00
// State breakpoint box
+ SHorizontalBox : : Slot ( )
. VAlign ( VAlign_Top )
. HAlign ( HAlign_Left )
. AutoWidth ( )
2023-06-15 11:38:28 -04:00
[
2024-08-01 05:38:41 -04:00
SNew ( SBox )
. Padding ( FMargin ( - 12.f , - 6.f , 0.f , 0.f ) )
[
SNew ( SImage )
. DesiredSizeOverride ( FVector2D ( 12.f , 12.f ) )
. Image ( FStateTreeEditorStyle : : Get ( ) . GetBrush ( TEXT ( " StateTreeEditor.Debugger.Breakpoint.EnabledAndValid " ) ) )
. Visibility ( this , & SStateTreeViewRow : : GetStateBreakpointVisibility )
. ToolTipText ( this , & SStateTreeViewRow : : GetStateBreakpointTooltipText )
]
2023-06-15 11:38:28 -04:00
]
2023-03-14 13:35:46 -04:00
]
]
]
2022-06-30 03:06:38 -04:00
]
]
2023-04-12 07:59:16 -04:00
2022-06-30 03:06:38 -04:00
+ SHorizontalBox : : Slot ( )
2023-04-12 07:59:16 -04:00
. VAlign ( VAlign_Fill )
2024-08-01 05:38:41 -04:00
. HAlign ( HAlign_Left )
2022-06-30 03:06:38 -04:00
[
2024-08-01 05:38:41 -04:00
// Transitions
SNew ( SHorizontalBox )
2021-09-28 13:33:17 -04:00
2024-08-01 05:38:41 -04:00
+ SHorizontalBox : : Slot ( )
. VAlign ( VAlign_Top )
. AutoWidth ( )
[
SNew ( SBox )
. HeightOverride ( UE : : StateTree : : Editor : : StateRowHeight )
. Visibility ( this , & SStateTreeViewRow : : GetTransitionDashVisibility )
. VAlign ( VAlign_Center )
[
SNew ( SImage )
. Image ( FStateTreeEditorStyle : : Get ( ) . GetBrush ( " StateTreeEditor.Transition.Dash " ) )
. ColorAndOpacity ( IconTint )
2023-04-12 07:59:16 -04:00
]
]
2024-08-01 05:38:41 -04:00
// Completed transitions
+ SHorizontalBox : : Slot ( )
. VAlign ( VAlign_Top )
. AutoWidth ( )
2023-06-05 13:12:19 -04:00
[
2024-08-01 05:38:41 -04:00
MakeTransitionWidget ( EStateTreeTransitionTrigger : : OnStateCompleted , nullptr )
]
// Succeeded transitions
+ SHorizontalBox : : Slot ( )
. VAlign ( VAlign_Top )
. AutoWidth ( )
[
MakeTransitionWidget ( EStateTreeTransitionTrigger : : OnStateSucceeded , FStateTreeEditorStyle : : Get ( ) . GetBrush ( " StateTreeEditor.Transition.Succeeded " ) )
]
// Failed transitions
+ SHorizontalBox : : Slot ( )
. VAlign ( VAlign_Top )
. AutoWidth ( )
[
MakeTransitionWidget ( EStateTreeTransitionTrigger : : OnStateFailed , FStateTreeEditorStyle : : Get ( ) . GetBrush ( " StateTreeEditor.Transition.Failed " ) )
]
// Transitions
+ SHorizontalBox : : Slot ( )
. VAlign ( VAlign_Top )
. AutoWidth ( )
[
MakeTransitionWidget ( EStateTreeTransitionTrigger : : OnTick | EStateTreeTransitionTrigger : : OnEvent , FStateTreeEditorStyle : : Get ( ) . GetBrush ( " StateTreeEditor.Transition.Condition " ) )
2023-06-05 13:12:19 -04:00
]
]
2022-04-05 03:20:57 -04:00
]
]
2024-08-01 05:38:41 -04:00
+ SVerticalBox : : Slot ( )
. AutoHeight ( )
. Padding ( FMargin ( 0 , 2 , 0 , 0 ) )
2022-06-30 03:06:38 -04:00
[
2024-08-01 05:38:41 -04:00
MakeConditionsWidget ( ViewBox )
2022-06-30 03:06:38 -04:00
]
2024-08-01 05:38:41 -04:00
+ SVerticalBox : : Slot ( )
. AutoHeight ( )
. Padding ( FMargin ( 0 , 2 , 0 , 0 ) )
2022-06-30 03:06:38 -04:00
[
2024-08-01 05:38:41 -04:00
MakeTasksWidget ( ViewBox )
2022-06-30 03:06:38 -04:00
]
2021-09-28 13:33:17 -04:00
]
]
] ;
}
2024-08-01 05:38:41 -04:00
TSharedRef < SWidget > SStateTreeViewRow : : MakeTasksWidget ( const TSharedPtr < SScrollBox > & ViewBox )
2023-06-05 13:12:19 -04:00
{
2024-04-05 03:37:02 -04:00
const UStateTreeEditorData * EditorData = WeakEditorData . Get ( ) ;
2023-06-05 13:12:19 -04:00
const UStateTreeState * State = WeakState . Get ( ) ;
2024-08-01 05:38:41 -04:00
if ( ! EditorData | | ! State )
2023-06-05 13:12:19 -04:00
{
2024-08-01 05:38:41 -04:00
return SNullWidget : : NullWidget ;
}
const TSharedRef < SWrapBox > TasksBox = SNew ( SWrapBox )
. PreferredSize_Lambda ( [ WeakOwnerViewBox = ViewBox . ToWeakPtr ( ) ] ( )
{
// Captured as weak ptr so we don't prevent our parent widget from being destroyed (circular pointer reference).
if ( const TSharedPtr < SScrollBox > OwnerViewBox = WeakOwnerViewBox . Pin ( ) )
{
return FMath : : Max ( 300 , OwnerViewBox - > GetTickSpaceGeometry ( ) . GetLocalSize ( ) . X - 200 ) ;
}
return 0.f ;
} ) ;
if ( State - > Tasks . IsEmpty ( ) )
{
return SNullWidget : : NullWidget ;
2023-06-05 13:12:19 -04:00
}
2024-04-05 03:37:02 -04:00
const int32 NumTasks = State - > Tasks . Num ( ) ;
2023-06-15 11:38:28 -04:00
2024-08-01 05:38:41 -04:00
// The task descriptions can get long. Make some effort to limit how long they can get.
2024-04-05 03:37:02 -04:00
for ( int32 TaskIndex = 0 ; TaskIndex < NumTasks ; TaskIndex + + )
2023-06-05 13:12:19 -04:00
{
2024-04-05 03:37:02 -04:00
const FStateTreeEditorNode & TaskNode = State - > Tasks [ TaskIndex ] ;
if ( const FStateTreeTaskBase * Task = TaskNode . Node . GetPtr < FStateTreeTaskBase > ( ) )
2023-06-05 13:12:19 -04:00
{
2024-08-01 05:38:41 -04:00
const FGuid TaskId = State - > Tasks [ TaskIndex ] . ID ;
auto IsTaskEnabledFunc = [ WeakState = WeakState , TaskIndex ]
2023-06-05 13:12:19 -04:00
{
const UStateTreeState * State = WeakState . Get ( ) ;
if ( State ! = nullptr & & State - > Tasks . IsValidIndex ( TaskIndex ) )
{
if ( const FStateTreeTaskBase * Task = State - > Tasks [ TaskIndex ] . Node . GetPtr < FStateTreeTaskBase > ( ) )
{
return ( State - > bEnabled & & Task - > bTaskEnabled ) ;
}
2023-06-15 11:38:28 -04:00
}
2023-06-05 13:12:19 -04:00
return true ;
} ;
2023-06-15 11:38:28 -04:00
2024-04-05 03:37:02 -04:00
auto IsTaskBreakpointEnabledFunc = [ WeakEditorData = WeakEditorData , TaskId ]
2023-06-15 11:38:28 -04:00
{
2024-05-02 11:47:26 -04:00
# if WITH_STATETREE_TRACE_DEBUGGER
2023-06-15 11:38:28 -04:00
const UStateTreeEditorData * EditorData = WeakEditorData . Get ( ) ;
if ( EditorData ! = nullptr & & EditorData - > HasAnyBreakpoint ( TaskId ) )
{
return EVisibility : : Visible ;
}
2024-05-02 11:47:26 -04:00
# endif // WITH_STATETREE_TRACE_DEBUGGER
2023-06-15 11:38:28 -04:00
return EVisibility : : Hidden ;
} ;
2023-06-05 13:12:19 -04:00
2024-04-05 03:37:02 -04:00
auto GetTaskBreakpointTooltipFunc = [ WeakEditorData = WeakEditorData , TaskId ]
2023-06-15 11:38:28 -04:00
{
2024-05-02 11:47:26 -04:00
# if WITH_STATETREE_TRACE_DEBUGGER
2023-06-15 11:38:28 -04:00
if ( const UStateTreeEditorData * EditorData = WeakEditorData . Get ( ) )
{
const bool bHasBreakpointOnEnter = EditorData - > HasBreakpoint ( TaskId , EStateTreeBreakpointType : : OnEnter ) ;
const bool bHasBreakpointOnExit = EditorData - > HasBreakpoint ( TaskId , EStateTreeBreakpointType : : OnExit ) ;
if ( bHasBreakpointOnEnter & & bHasBreakpointOnExit )
{
return LOCTEXT ( " StateTreeTaskBreakpointOnEnterAndOnExitTooltip " , " Break when entering or exiting task " ) ;
}
if ( bHasBreakpointOnEnter )
{
return LOCTEXT ( " StateTreeTaskBreakpointOnEnterTooltip " , " Break when entering task " ) ;
}
if ( bHasBreakpointOnExit )
{
return LOCTEXT ( " StateTreeTaskBreakpointOnExitTooltip " , " Break when exiting task " ) ;
}
}
2024-05-02 11:47:26 -04:00
# endif // WITH_STATETREE_TRACE_DEBUGGER
2023-06-15 11:38:28 -04:00
return FText : : GetEmpty ( ) ;
} ;
2023-06-05 13:12:19 -04:00
TasksBox - > AddSlot ( )
2024-08-01 05:38:41 -04:00
. Padding ( FMargin ( 0 , 0 , 6 , 0 ) )
2023-06-05 13:12:19 -04:00
[
2024-08-01 05:38:41 -04:00
SNew ( SButton )
. ButtonStyle ( FAppStyle : : Get ( ) , " SimpleButton " )
. ContentPadding ( FMargin ( 0 , 0 ) )
. OnClicked_Lambda ( [ StateTreeViewModel = StateTreeViewModel , WeakState = WeakState , TaskId ] ( )
{
StateTreeViewModel - > BringNodeToFocus ( WeakState . Get ( ) , TaskId ) ;
return FReply : : Handled ( ) ;
} )
2023-06-05 13:12:19 -04:00
[
2024-08-01 05:38:41 -04:00
SNew ( SBorder )
. VAlign ( VAlign_Center )
. BorderImage ( FAppStyle : : GetNoBrush ( ) )
. Padding ( 0 )
. IsEnabled_Lambda ( IsTaskEnabledFunc )
2023-06-15 11:38:28 -04:00
[
2024-08-01 05:38:41 -04:00
SNew ( SOverlay )
+ SOverlay : : Slot ( )
2024-04-05 03:37:02 -04:00
[
2024-08-01 05:38:41 -04:00
SNew ( SBox )
. HeightOverride ( UE : : StateTree : : Editor : : TaskRowHeight )
. Padding ( FMargin ( 0.f , 0.f ) )
[
SNew ( SHorizontalBox )
+ SHorizontalBox : : Slot ( )
. VAlign ( VAlign_Center )
. HAlign ( HAlign_Left )
. FillContentWidth ( 0.f , 0.f )
[
SNew ( SBox )
. Padding ( FMargin ( 0.f , 0.f , 2.f , 0.f ) )
. Visibility ( this , & SStateTreeViewRow : : GetTaskIconVisibility , TaskId )
[
SNew ( SImage )
. Image ( this , & SStateTreeViewRow : : GetTaskIcon , TaskId )
. ColorAndOpacity ( this , & SStateTreeViewRow : : GetTaskIconColor , TaskId )
]
]
+ SHorizontalBox : : Slot ( )
. VAlign ( VAlign_Center )
. HAlign ( HAlign_Left )
. FillContentWidth ( 0.f , 1.f )
[
SNew ( SRichTextBlock )
. Text ( this , & SStateTreeViewRow : : GetTaskDesc , TaskId , EStateTreeNodeFormatting : : RichText )
. ToolTipText ( this , & SStateTreeViewRow : : GetTaskDesc , TaskId , EStateTreeNodeFormatting : : Text )
. TextStyle ( & FStateTreeEditorStyle : : Get ( ) . GetWidgetStyle < FTextBlockStyle > ( " StateTree.Task.Title " ) )
. OverflowPolicy ( ETextOverflowPolicy : : Ellipsis )
. Clipping ( EWidgetClipping : : OnDemand )
+ SRichTextBlock : : Decorator ( FTextStyleDecorator : : Create ( TEXT ( " " ) , FStateTreeEditorStyle : : Get ( ) . GetWidgetStyle < FTextBlockStyle > ( " StateTree.Task.Title " ) ) )
+ SRichTextBlock : : Decorator ( FTextStyleDecorator : : Create ( TEXT ( " b " ) , FStateTreeEditorStyle : : Get ( ) . GetWidgetStyle < FTextBlockStyle > ( " StateTree.Task.Title.Bold " ) ) )
+ SRichTextBlock : : Decorator ( FTextStyleDecorator : : Create ( TEXT ( " s " ) , FStateTreeEditorStyle : : Get ( ) . GetWidgetStyle < FTextBlockStyle > ( " StateTree.Task.Title.Subdued " ) ) )
]
]
]
+ SOverlay : : Slot ( )
[
// Task Breakpoint box
2024-04-17 03:01:36 -04:00
SNew ( SHorizontalBox )
+ SHorizontalBox : : Slot ( )
2024-08-01 05:38:41 -04:00
. VAlign ( VAlign_Top )
2024-04-17 03:01:36 -04:00
. HAlign ( HAlign_Left )
. AutoWidth ( )
[
SNew ( SBox )
2024-08-01 05:38:41 -04:00
. Padding ( FMargin ( - 2.0f , - 2.0f , 0.0f , 0.0f ) )
2024-04-17 03:01:36 -04:00
[
SNew ( SImage )
2024-08-01 05:38:41 -04:00
. DesiredSizeOverride ( FVector2D ( 10.f , 10.f ) )
. Image ( FStateTreeEditorStyle : : Get ( ) . GetBrush ( TEXT ( " StateTreeEditor.Debugger.Breakpoint.EnabledAndValid " ) ) )
. Visibility_Lambda ( IsTaskBreakpointEnabledFunc )
. ToolTipText_Lambda ( GetTaskBreakpointTooltipFunc )
2024-04-17 03:01:36 -04:00
]
]
2023-06-15 11:38:28 -04:00
]
]
2023-06-05 13:12:19 -04:00
]
] ;
}
}
return TasksBox ;
}
2024-08-01 05:38:41 -04:00
TSharedRef < SWidget > SStateTreeViewRow : : MakeConditionsWidget ( const TSharedPtr < SScrollBox > & ViewBox )
{
const UStateTreeEditorData * EditorData = WeakEditorData . Get ( ) ;
const UStateTreeState * State = WeakState . Get ( ) ;
if ( ! EditorData | | ! State )
{
return SNullWidget : : NullWidget ;
}
const TSharedRef < SWrapBox > ConditionsBox = SNew ( SWrapBox )
. PreferredSize_Lambda ( [ WeakOwnerViewBox = ViewBox . ToWeakPtr ( ) ] ( )
{
// Captured as weak ptr so we don't prevent our parent widget from being destroyed (circular pointer reference).
if ( const TSharedPtr < SScrollBox > OwnerViewBox = WeakOwnerViewBox . Pin ( ) )
{
return FMath : : Max ( 300 , OwnerViewBox - > GetTickSpaceGeometry ( ) . GetLocalSize ( ) . X - 200 ) ;
}
return 0.f ;
} ) ;
if ( State - > EnterConditions . IsEmpty ( ) )
{
return SNullWidget : : NullWidget ;
}
const int32 NumConditions = State - > EnterConditions . Num ( ) ;
for ( int32 ConditionIndex = 0 ; ConditionIndex < NumConditions ; ConditionIndex + + )
{
const FStateTreeEditorNode & ConditionNode = State - > EnterConditions [ ConditionIndex ] ;
if ( const FStateTreeConditionBase * Condition = ConditionNode . Node . GetPtr < FStateTreeConditionBase > ( ) )
{
const FGuid ConditionId = ConditionNode . ID ;
auto IsConditionEnabledFunc = [ WeakState = WeakState ]
{
const UStateTreeState * State = WeakState . Get ( ) ;
return State & & State - > bEnabled ;
} ;
auto IsForcedConditionVisibleFunc = [ WeakState = WeakState , ConditionIndex ] ( )
{
const UStateTreeState * State = WeakState . Get ( ) ;
if ( State ! = nullptr & & State - > EnterConditions . IsValidIndex ( ConditionIndex ) )
{
if ( const FStateTreeConditionBase * Condition = State - > EnterConditions [ ConditionIndex ] . Node . GetPtr < FStateTreeConditionBase > ( ) )
{
return Condition - > EvaluationMode ! = EStateTreeConditionEvaluationMode : : Evaluated ? EVisibility : : Visible : EVisibility : : Hidden ;
}
}
return EVisibility : : Hidden ;
} ;
auto GetForcedConditionTooltipFunc = [ WeakState = WeakState , ConditionIndex ] ( )
{
const UStateTreeState * State = WeakState . Get ( ) ;
if ( State ! = nullptr & & State - > EnterConditions . IsValidIndex ( ConditionIndex ) )
{
if ( const FStateTreeConditionBase * Condition = State - > EnterConditions [ ConditionIndex ] . Node . GetPtr < FStateTreeConditionBase > ( ) )
{
if ( Condition - > EvaluationMode = = EStateTreeConditionEvaluationMode : : ForcedTrue )
{
return LOCTEXT ( " ForcedTrueConditionTooltip " , " This condition is not evaluated and result forced to 'true'. " ) ;
}
if ( Condition - > EvaluationMode = = EStateTreeConditionEvaluationMode : : ForcedFalse )
{
return LOCTEXT ( " ForcedFalseConditionTooltip " , " This condition is not evaluated and result forced to 'false'. " ) ;
}
}
}
return FText : : GetEmpty ( ) ;
} ;
auto GetForcedConditionImageFunc = [ WeakState = WeakState , ConditionIndex ] ( ) - > const FSlateBrush *
{
const UStateTreeState * State = WeakState . Get ( ) ;
if ( State ! = nullptr & & State - > EnterConditions . IsValidIndex ( ConditionIndex ) )
{
if ( const FStateTreeConditionBase * Condition = State - > EnterConditions [ ConditionIndex ] . Node . GetPtr < FStateTreeConditionBase > ( ) )
{
if ( Condition - > EvaluationMode = = EStateTreeConditionEvaluationMode : : ForcedTrue )
{
return FStateTreeEditorStyle : : Get ( ) . GetBrush ( " StateTreeEditor.Debugger.Condition.Passed " ) ;
}
if ( Condition - > EvaluationMode = = EStateTreeConditionEvaluationMode : : ForcedFalse )
{
return FStateTreeEditorStyle : : Get ( ) . GetBrush ( " StateTreeEditor.Debugger.Condition.Failed " ) ;
}
}
}
return nullptr ;
} ;
ConditionsBox - > AddSlot ( )
[
SNew ( SBorder )
. VAlign ( VAlign_Center )
. BorderImage ( FAppStyle : : GetNoBrush ( ) )
. IsEnabled_Lambda ( IsConditionEnabledFunc )
. Padding ( 0 )
[
SNew ( SBox )
. HeightOverride ( UE : : StateTree : : Editor : : TaskRowHeight )
[
SNew ( SHorizontalBox )
// Operand
+ SHorizontalBox : : Slot ( )
. AutoWidth ( )
. VAlign ( VAlign_Center )
[
SNew ( SBox )
. Padding ( FMargin ( 4 , 2 , 4 , 0 ) )
. VAlign ( VAlign_Center )
[
SNew ( STextBlock )
. TextStyle ( FStateTreeEditorStyle : : Get ( ) , " StateTree.Node.Operand " )
. Text ( this , & SStateTreeViewRow : : GetOperandText , ConditionIndex )
]
]
// Open parens
+ SHorizontalBox : : Slot ( )
. AutoWidth ( )
. VAlign ( VAlign_Center )
[
SNew ( SBox )
. Padding ( FMargin ( FMargin ( 0.0f , 1.0f , 0.0f , 0.0f ) ) )
[
SNew ( STextBlock )
. TextStyle ( FStateTreeEditorStyle : : Get ( ) , " StateTree.Task.Title " )
. Text ( this , & SStateTreeViewRow : : GetOpenParens , ConditionIndex )
]
]
// Open parens
+ SHorizontalBox : : Slot ( )
. AutoWidth ( )
. VAlign ( VAlign_Center )
[
SNew ( SOverlay )
+ SOverlay : : Slot ( )
[
SNew ( SButton )
. ButtonStyle ( FAppStyle : : Get ( ) , " SimpleButton " )
. ContentPadding ( FMargin ( 2.f , 0.f ) )
. OnClicked_Lambda ( [ StateTreeViewModel = StateTreeViewModel , WeakState = WeakState , ConditionId ] ( )
{
StateTreeViewModel - > BringNodeToFocus ( WeakState . Get ( ) , ConditionId ) ;
return FReply : : Handled ( ) ;
} )
[
SNew ( SHorizontalBox )
// Icon
+ SHorizontalBox : : Slot ( )
. VAlign ( VAlign_Center )
. HAlign ( HAlign_Left )
. AutoWidth ( )
[
SNew ( SBox )
. Padding ( FMargin ( 0.f , 0.f , 2.f , 0.f ) )
. Visibility ( this , & SStateTreeViewRow : : GetConditionIconVisibility , ConditionId )
[
SNew ( SImage )
. Image ( this , & SStateTreeViewRow : : GetConditionIcon , ConditionId )
. ColorAndOpacity ( this , & SStateTreeViewRow : : GetConditionIconColor , ConditionId )
]
]
// Desc
+ SHorizontalBox : : Slot ( )
. VAlign ( VAlign_Center )
. HAlign ( HAlign_Left )
. AutoWidth ( )
[
SNew ( SRichTextBlock )
. Text ( this , & SStateTreeViewRow : : GetConditionDesc , ConditionId , EStateTreeNodeFormatting : : RichText )
. ToolTipText ( this , & SStateTreeViewRow : : GetConditionDesc , ConditionId , EStateTreeNodeFormatting : : Text )
. TextStyle ( & FStateTreeEditorStyle : : Get ( ) . GetWidgetStyle < FTextBlockStyle > ( " StateTree.Task.Title " ) )
. OverflowPolicy ( ETextOverflowPolicy : : Ellipsis )
. Clipping ( EWidgetClipping : : OnDemand )
+ SRichTextBlock : : Decorator ( FTextStyleDecorator : : Create ( TEXT ( " " ) , FStateTreeEditorStyle : : Get ( ) . GetWidgetStyle < FTextBlockStyle > ( " StateTree.Task.Title " ) ) )
+ SRichTextBlock : : Decorator ( FTextStyleDecorator : : Create ( TEXT ( " b " ) , FStateTreeEditorStyle : : Get ( ) . GetWidgetStyle < FTextBlockStyle > ( " StateTree.Task.Title.Bold " ) ) )
+ SRichTextBlock : : Decorator ( FTextStyleDecorator : : Create ( TEXT ( " s " ) , FStateTreeEditorStyle : : Get ( ) . GetWidgetStyle < FTextBlockStyle > ( " StateTree.Task.Title.Subdued " ) ) )
]
]
]
+ SOverlay : : Slot ( )
[
// Condition override box
SNew ( SHorizontalBox )
+ SHorizontalBox : : Slot ( )
. VAlign ( VAlign_Top )
. HAlign ( HAlign_Left )
. AutoWidth ( )
[
SNew ( SBox )
. Padding ( FMargin ( - 2.0f , - 2.0f , 0.0f , 0.0f ) )
[
SNew ( SImage )
. DesiredSizeOverride ( FVector2D ( 16.f , 16.f ) )
. Image_Lambda ( GetForcedConditionImageFunc )
. Visibility_Lambda ( IsForcedConditionVisibleFunc )
. ToolTipText_Lambda ( GetForcedConditionTooltipFunc )
]
]
]
]
// Close parens
+ SHorizontalBox : : Slot ( )
. AutoWidth ( )
. VAlign ( VAlign_Center )
[
SNew ( SBox )
. Padding ( FMargin ( 0.0f , 1.0f , 0.0f , 0.0f ) )
[
SNew ( STextBlock )
. TextStyle ( FStateTreeEditorStyle : : Get ( ) , " StateTree.Task.Title " )
. Text ( this , & SStateTreeViewRow : : GetCloseParens , ConditionIndex )
]
]
]
]
] ;
}
}
return ConditionsBox ;
}
2022-09-01 09:06:53 -04:00
void SStateTreeViewRow : : RequestRename ( ) const
2021-09-28 13:33:17 -04:00
{
if ( NameTextBlock )
{
NameTextBlock - > EnterEditingMode ( ) ;
}
}
2024-04-17 03:01:36 -04:00
FSlateColor SStateTreeViewRow : : GetTitleColor ( const float Alpha , const float Lighten ) const
2021-09-28 13:33:17 -04:00
{
2023-09-26 11:50:26 -04:00
const UStateTreeState * State = WeakState . Get ( ) ;
2024-04-05 03:37:02 -04:00
const UStateTreeEditorData * EditorData = WeakEditorData . Get ( ) ;
2023-09-26 11:50:26 -04:00
2024-04-17 03:01:36 -04:00
FLinearColor Color ( FColor ( 31 , 151 , 167 ) ) ;
2023-09-26 11:50:26 -04:00
if ( State ! = nullptr & & EditorData ! = nullptr )
2021-09-28 13:33:17 -04:00
{
2023-09-26 11:50:26 -04:00
if ( const FStateTreeEditorColor * FoundColor = EditorData - > FindColor ( State - > ColorRef ) )
2021-09-28 13:33:17 -04:00
{
2023-09-26 11:50:26 -04:00
if ( IsRootState ( ) | | State - > Type = = EStateTreeStateType : : Subtree )
{
2024-04-17 03:01:36 -04:00
Color = UE : : StateTree : : Editor : : LerpColorSRGB ( FoundColor - > Color , FColor : : Black , 0.25f ) ;
2023-09-26 11:50:26 -04:00
}
2024-08-01 05:38:41 -04:00
else
{
Color = FoundColor - > Color ;
}
2021-09-28 13:33:17 -04:00
}
}
2024-04-17 03:01:36 -04:00
if ( Lighten > 0.0f )
{
Color = UE : : StateTree : : Editor : : LerpColorSRGB ( Color , FColor : : White , Lighten ) ;
}
return Color . CopyWithNewOpacity ( Alpha ) ;
2021-09-28 13:33:17 -04:00
}
2023-03-14 13:35:46 -04:00
FSlateColor SStateTreeViewRow : : GetActiveStateColor ( ) const
{
if ( const UStateTreeState * State = WeakState . Get ( ) )
{
if ( StateTreeViewModel & & StateTreeViewModel - > IsStateActiveInDebugger ( * State ) )
{
return FLinearColor : : Yellow ;
}
2023-04-12 07:59:16 -04:00
if ( StateTreeViewModel & & StateTreeViewModel - > IsSelected ( State ) )
{
2024-08-01 05:38:41 -04:00
// @todo: change to the common selection color.
2023-04-12 07:59:16 -04:00
return FLinearColor ( FColor ( 236 , 134 , 39 ) ) ;
}
}
return FLinearColor : : Transparent ;
}
FSlateColor SStateTreeViewRow : : GetSubTreeMarkerColor ( ) const
{
// Show color for subtree.
if ( const UStateTreeState * State = WeakState . Get ( ) )
{
if ( IsRootState ( ) | | State - > Type = = EStateTreeStateType : : Subtree )
{
2023-09-26 11:50:26 -04:00
const FSlateColor TitleColor = GetTitleColor ( ) ;
return UE : : StateTree : : Editor : : LerpColorSRGB ( TitleColor . GetSpecifiedColor ( ) , FLinearColor : : White , 0.2f ) ;
2023-04-12 07:59:16 -04:00
}
2023-03-14 13:35:46 -04:00
}
return GetTitleColor ( ) ;
}
2024-08-01 05:38:41 -04:00
EVisibility SStateTreeViewRow : : GetSubTreeVisibility ( ) const
{
if ( const UStateTreeState * State = WeakState . Get ( ) )
{
if ( IsRootState ( ) | | State - > Type = = EStateTreeStateType : : Subtree )
{
return EVisibility : : Visible ;
}
}
return EVisibility : : Collapsed ;
}
2021-09-28 13:33:17 -04:00
FText SStateTreeViewRow : : GetStateDesc ( ) const
{
if ( const UStateTreeState * State = WeakState . Get ( ) )
{
return FText : : FromName ( State - > Name ) ;
}
return FText : : FromName ( FName ( ) ) ;
}
2023-06-21 10:32:41 -04:00
FText SStateTreeViewRow : : GetStateIDDesc ( ) const
{
if ( const UStateTreeState * State = WeakState . Get ( ) )
{
return FText : : FromString ( * LexToString ( State - > ID ) ) ;
}
return FText : : FromName ( FName ( ) ) ;
}
2021-09-28 13:33:17 -04:00
EVisibility SStateTreeViewRow : : GetConditionVisibility ( ) const
{
if ( const UStateTreeState * State = WeakState . Get ( ) )
{
2021-10-21 04:08:20 -04:00
return State - > EnterConditions . Num ( ) > 0 ? EVisibility : : Visible : EVisibility : : Collapsed ;
2021-09-28 13:33:17 -04:00
}
return EVisibility : : Collapsed ;
}
2023-06-15 11:38:28 -04:00
EVisibility SStateTreeViewRow : : GetStateBreakpointVisibility ( ) const
2023-03-14 13:35:46 -04:00
{
2024-05-02 11:47:26 -04:00
# if WITH_STATETREE_TRACE_DEBUGGER
2023-06-15 11:38:28 -04:00
const UStateTreeState * State = WeakState . Get ( ) ;
2024-04-05 03:37:02 -04:00
const UStateTreeEditorData * EditorData = WeakEditorData . Get ( ) ;
2023-06-15 11:38:28 -04:00
if ( State ! = nullptr & & EditorData ! = nullptr )
2023-03-14 13:35:46 -04:00
{
2023-06-15 11:38:28 -04:00
return ( EditorData ! = nullptr & & EditorData - > HasAnyBreakpoint ( State - > ID ) ) ? EVisibility : : Visible : EVisibility : : Hidden ;
}
2024-05-02 11:47:26 -04:00
# endif // WITH_STATETREE_TRACE_DEBUGGER
2023-06-15 11:38:28 -04:00
return EVisibility : : Hidden ;
}
FText SStateTreeViewRow : : GetStateBreakpointTooltipText ( ) const
{
2024-05-02 11:47:26 -04:00
# if WITH_STATETREE_TRACE_DEBUGGER
2023-06-15 11:38:28 -04:00
const UStateTreeState * State = WeakState . Get ( ) ;
2024-04-05 03:37:02 -04:00
const UStateTreeEditorData * EditorData = WeakEditorData . Get ( ) ;
2023-06-15 11:38:28 -04:00
if ( State ! = nullptr & & EditorData ! = nullptr )
{
const bool bHasBreakpointOnEnter = EditorData - > HasBreakpoint ( State - > ID , EStateTreeBreakpointType : : OnEnter ) ;
const bool bHasBreakpointOnExit = EditorData - > HasBreakpoint ( State - > ID , EStateTreeBreakpointType : : OnExit ) ;
if ( bHasBreakpointOnEnter & & bHasBreakpointOnExit )
2023-03-14 13:35:46 -04:00
{
2023-06-15 11:38:28 -04:00
return LOCTEXT ( " StateTreeStateBreakpointOnEnterAndOnExitTooltip " , " Break when entering or exiting state " ) ;
}
if ( bHasBreakpointOnEnter )
{
return LOCTEXT ( " StateTreeStateBreakpointOnEnterTooltip " , " Break when entering state " ) ;
}
if ( bHasBreakpointOnExit )
{
return LOCTEXT ( " StateTreeStateBreakpointOnExitTooltip " , " Break when exiting state " ) ;
2023-03-14 13:35:46 -04:00
}
}
2024-05-02 11:47:26 -04:00
# endif // WITH_STATETREE_TRACE_DEBUGGER
2023-06-15 11:38:28 -04:00
return FText : : GetEmpty ( ) ;
2023-03-14 13:35:46 -04:00
}
2022-04-28 03:54:07 -04:00
2023-04-12 07:59:16 -04:00
const FSlateBrush * SStateTreeViewRow : : GetSelectorIcon ( ) const
2022-04-28 03:54:07 -04:00
{
if ( const UStateTreeState * State = WeakState . Get ( ) )
{
2024-08-13 09:09:54 -04:00
return FStateTreeEditorStyle : : GetBrushForSelectionBehaviorType ( State - > SelectionBehavior , ! State - > Children . IsEmpty ( ) , State - > Type ) ;
2022-04-28 03:54:07 -04:00
}
2023-04-12 07:59:16 -04:00
return nullptr ;
2022-04-28 03:54:07 -04:00
}
2023-04-12 07:59:16 -04:00
FText SStateTreeViewRow : : GetSelectorTooltip ( ) const
{
if ( const UStateTreeState * State = WeakState . Get ( ) )
{
const UEnum * Enum = StaticEnum < EStateTreeStateSelectionBehavior > ( ) ;
check ( Enum ) ;
const int32 Index = Enum - > GetIndexByValue ( ( int64 ) State - > SelectionBehavior ) ;
2024-06-13 22:57:49 -04:00
switch ( State - > SelectionBehavior )
2023-04-12 07:59:16 -04:00
{
2024-06-13 22:57:49 -04:00
case EStateTreeStateSelectionBehavior : : None :
case EStateTreeStateSelectionBehavior : : TryEnterState :
case EStateTreeStateSelectionBehavior : : TryFollowTransitions :
2023-04-12 07:59:16 -04:00
return Enum - > GetToolTipTextByIndex ( Index ) ;
2024-06-13 22:57:49 -04:00
case EStateTreeStateSelectionBehavior : : TrySelectChildrenInOrder :
case EStateTreeStateSelectionBehavior : : TrySelectChildrenAtUniformRandom :
case EStateTreeStateSelectionBehavior : : TrySelectChildrenWithHighestUtility :
case EStateTreeStateSelectionBehavior : : TrySelectChildrenBasedOnRelativeUtility :
if ( State - > Children . IsEmpty ( )
| | State - > Type = = EStateTreeStateType : : Linked
| | State - > Type = = EStateTreeStateType : : LinkedAsset )
{
const int32 EnterStateIndex = Enum - > GetIndexByValue ( ( int64 ) EStateTreeStateSelectionBehavior : : TryEnterState ) ;
return FText : : Format ( LOCTEXT ( " ConvertedToEnterState " , " {0} \n Automatically converted from '{1}' because the State has no child States. " ) ,
Enum - > GetToolTipTextByIndex ( EnterStateIndex ) , UEnum : : GetDisplayValueAsText ( State - > SelectionBehavior ) ) ;
}
else
{
return Enum - > GetToolTipTextByIndex ( Index ) ;
}
default :
check ( false ) ;
2023-04-12 07:59:16 -04:00
}
}
return FText : : GetEmpty ( ) ;
}
FText SStateTreeViewRow : : GetStateTypeTooltip ( ) const
{
if ( const UStateTreeState * State = WeakState . Get ( ) )
{
const UEnum * Enum = StaticEnum < EStateTreeStateType > ( ) ;
check ( Enum ) ;
const int32 Index = Enum - > GetIndexByValue ( ( int64 ) State - > Type ) ;
return Enum - > GetToolTipTextByIndex ( Index ) ;
}
return FText : : GetEmpty ( ) ;
}
2024-04-17 03:01:36 -04:00
const FStateTreeEditorNode * SStateTreeViewRow : : GetTaskNodeByID ( FGuid TaskID ) const
2024-04-05 03:37:02 -04:00
{
const UStateTreeState * State = WeakState . Get ( ) ;
const UStateTreeEditorData * EditorData = WeakEditorData . Get ( ) ;
if ( EditorData ! = nullptr
& & State ! = nullptr )
{
2024-04-17 03:01:36 -04:00
return State - > Tasks . FindByPredicate ( [ & TaskID ] ( const FStateTreeEditorNode & Node )
2024-04-05 03:37:02 -04:00
{
return Node . ID = = TaskID ;
} ) ;
2024-04-17 03:01:36 -04:00
}
return nullptr ;
}
EVisibility SStateTreeViewRow : : GetTaskIconVisibility ( FGuid TaskID ) const
{
bool bHasIcon = false ;
if ( const FStateTreeEditorNode * TaskNode = GetTaskNodeByID ( TaskID ) )
{
if ( const FStateTreeNodeBase * BaseNode = TaskNode - > Node . GetPtr < const FStateTreeNodeBase > ( ) )
{
bHasIcon = ! BaseNode - > GetIconName ( ) . IsNone ( ) ;
}
}
return bHasIcon ? EVisibility : : Visible : EVisibility : : Collapsed ;
}
const FSlateBrush * SStateTreeViewRow : : GetTaskIcon ( FGuid TaskID ) const
{
if ( const FStateTreeEditorNode * TaskNode = GetTaskNodeByID ( TaskID ) )
{
if ( const FStateTreeNodeBase * BaseNode = TaskNode - > Node . GetPtr < const FStateTreeNodeBase > ( ) )
{
return UE : : StateTreeEditor : : EditorNodeUtils : : ParseIcon ( BaseNode - > GetIconName ( ) ) . GetIcon ( ) ;
}
}
return nullptr ;
}
FSlateColor SStateTreeViewRow : : GetTaskIconColor ( FGuid TaskID ) const
{
if ( const FStateTreeEditorNode * TaskNode = GetTaskNodeByID ( TaskID ) )
{
if ( const FStateTreeNodeBase * BaseNode = TaskNode - > Node . GetPtr < const FStateTreeNodeBase > ( ) )
{
return FLinearColor ( BaseNode - > GetIconColor ( ) ) ;
}
}
return FSlateColor : : UseForeground ( ) ;
}
FText SStateTreeViewRow : : GetTaskDesc ( FGuid TaskID , EStateTreeNodeFormatting Formatting ) const
{
FText TaskName ;
if ( const UStateTreeEditorData * EditorData = WeakEditorData . Get ( ) )
{
if ( const FStateTreeEditorNode * TaskNode = GetTaskNodeByID ( TaskID ) )
2024-04-05 03:37:02 -04:00
{
if ( UE : : StateTree : : Editor : : GbDisplayItemIds )
{
2024-08-01 05:38:41 -04:00
TaskName = FText : : Format ( LOCTEXT ( " NodeNameWithID " , " {0} ({1}) " ) , EditorData - > GetNodeDescription ( * TaskNode , Formatting ) , FText : : AsCultureInvariant ( * LexToString ( TaskID ) ) ) ;
2024-04-05 03:37:02 -04:00
}
else
{
TaskName = EditorData - > GetNodeDescription ( * TaskNode , Formatting ) ;
}
}
}
return TaskName ;
}
2023-04-12 07:59:16 -04:00
2024-08-01 05:38:41 -04:00
const FStateTreeEditorNode * SStateTreeViewRow : : GetConditionNodeByID ( FGuid ConditionID ) const
2021-09-28 13:33:17 -04:00
{
2024-08-01 05:38:41 -04:00
const UStateTreeState * State = WeakState . Get ( ) ;
const UStateTreeEditorData * EditorData = WeakEditorData . Get ( ) ;
if ( EditorData ! = nullptr
& & State ! = nullptr )
2021-09-28 13:33:17 -04:00
{
2024-08-01 05:38:41 -04:00
return State - > EnterConditions . FindByPredicate ( [ & ConditionID ] ( const FStateTreeEditorNode & Node )
2021-09-28 13:33:17 -04:00
{
2024-08-01 05:38:41 -04:00
return Node . ID = = ConditionID ;
} ) ;
}
return nullptr ;
}
EVisibility SStateTreeViewRow : : GetConditionIconVisibility ( FGuid ConditionID ) const
{
bool bHasIcon = false ;
if ( const FStateTreeEditorNode * Node = GetConditionNodeByID ( ConditionID ) )
{
if ( const FStateTreeNodeBase * BaseNode = Node - > Node . GetPtr < const FStateTreeNodeBase > ( ) )
{
bHasIcon = ! BaseNode - > GetIconName ( ) . IsNone ( ) ;
}
}
return bHasIcon ? EVisibility : : Visible : EVisibility : : Collapsed ;
}
const FSlateBrush * SStateTreeViewRow : : GetConditionIcon ( FGuid ConditionID ) const
{
if ( const FStateTreeEditorNode * Node = GetConditionNodeByID ( ConditionID ) )
{
if ( const FStateTreeNodeBase * BaseNode = Node - > Node . GetPtr < const FStateTreeNodeBase > ( ) )
{
return UE : : StateTreeEditor : : EditorNodeUtils : : ParseIcon ( BaseNode - > GetIconName ( ) ) . GetIcon ( ) ;
}
}
return nullptr ;
}
FSlateColor SStateTreeViewRow : : GetConditionIconColor ( FGuid ConditionID ) const
{
if ( const FStateTreeEditorNode * Node = GetConditionNodeByID ( ConditionID ) )
{
if ( const FStateTreeNodeBase * BaseNode = Node - > Node . GetPtr < const FStateTreeNodeBase > ( ) )
{
return FLinearColor ( BaseNode - > GetIconColor ( ) ) ;
}
}
return FSlateColor : : UseForeground ( ) ;
}
FText SStateTreeViewRow : : GetConditionDesc ( FGuid ConditionID , EStateTreeNodeFormatting Formatting ) const
{
FText Description ;
if ( const UStateTreeEditorData * EditorData = WeakEditorData . Get ( ) )
{
if ( const FStateTreeEditorNode * Node = GetConditionNodeByID ( ConditionID ) )
{
if ( UE : : StateTree : : Editor : : GbDisplayItemIds )
2021-09-28 13:33:17 -04:00
{
2024-08-01 05:38:41 -04:00
Description = FText : : Format ( LOCTEXT ( " NodeNameWithID " , " {0} ({1}) " ) , EditorData - > GetNodeDescription ( * Node , Formatting ) , FText : : AsCultureInvariant ( * LexToString ( ConditionID ) ) ) ;
}
else
{
Description = EditorData - > GetNodeDescription ( * Node , Formatting ) ;
2021-09-28 13:33:17 -04:00
}
}
}
2024-08-01 05:38:41 -04:00
return Description ;
2021-09-28 13:33:17 -04:00
}
2024-08-01 05:38:41 -04:00
FText SStateTreeViewRow : : GetOperandText ( const int32 ConditionIndex ) const
{
const UStateTreeState * State = WeakState . Get ( ) ;
if ( ! State
| | ! State - > EnterConditions . IsValidIndex ( ConditionIndex ) )
{
return FText : : GetEmpty ( ) ;
}
// First item does not relate to anything existing, it could be empty.
// return IF to indicate that we're building condition and IS for consideration.
if ( ConditionIndex = = 0 )
{
return LOCTEXT ( " IfOperand " , " IF " ) ;
}
const EStateTreeExpressionOperand Operand = State - > EnterConditions [ ConditionIndex ] . ExpressionOperand ;
if ( Operand = = EStateTreeExpressionOperand : : And )
{
return LOCTEXT ( " AndOperand " , " AND " ) ;
}
else if ( Operand = = EStateTreeExpressionOperand : : Or )
{
return LOCTEXT ( " OrOperand " , " OR " ) ;
}
else
{
ensureMsgf ( false , TEXT ( " Unhandled operand %s " ) , * UEnum : : GetValueAsString ( Operand ) ) ;
}
return FText : : GetEmpty ( ) ;
}
FText SStateTreeViewRow : : GetOpenParens ( const int32 ConditionIndex ) const
{
const UStateTreeState * State = WeakState . Get ( ) ;
if ( ! State
| | ! State - > EnterConditions . IsValidIndex ( ConditionIndex ) )
{
return FText : : GetEmpty ( ) ;
}
const int32 NumConditions = State - > EnterConditions . Num ( ) ;
const int32 CurrIndent = ConditionIndex = = 0 ? 0 : ( State - > EnterConditions [ ConditionIndex ] . ExpressionIndent + 1 ) ;
const int32 NextIndent = ( ConditionIndex + 1 ) > = NumConditions ? 0 : ( State - > EnterConditions [ ConditionIndex + 1 ] . ExpressionIndent + 1 ) ;
const int32 DeltaIndent = NextIndent - CurrIndent ;
const int32 OpenParens = FMath : : Max ( 0 , DeltaIndent ) ;
static_assert ( UE : : StateTree : : MaxExpressionIndent = = 4 ) ;
switch ( OpenParens )
{
case 1 : return FText : : FromString ( TEXT ( " ( " ) ) ;
case 2 : return FText : : FromString ( TEXT ( " (( " ) ) ;
case 3 : return FText : : FromString ( TEXT ( " ((( " ) ) ;
case 4 : return FText : : FromString ( TEXT ( " (((( " ) ) ;
case 5 : return FText : : FromString ( TEXT ( " ((((( " ) ) ;
}
return FText : : GetEmpty ( ) ;
}
FText SStateTreeViewRow : : GetCloseParens ( const int32 ConditionIndex ) const
{
const UStateTreeState * State = WeakState . Get ( ) ;
if ( ! State
| | ! State - > EnterConditions . IsValidIndex ( ConditionIndex ) )
{
return FText : : GetEmpty ( ) ;
}
const int32 NumConditions = State - > EnterConditions . Num ( ) ;
const int32 CurrIndent = ConditionIndex = = 0 ? 0 : ( State - > EnterConditions [ ConditionIndex ] . ExpressionIndent + 1 ) ;
const int32 NextIndent = ( ConditionIndex + 1 ) > = NumConditions ? 0 : ( State - > EnterConditions [ ConditionIndex + 1 ] . ExpressionIndent + 1 ) ;
const int32 DeltaIndent = NextIndent - CurrIndent ;
const int32 CloseParens = FMath : : Max ( 0 , - DeltaIndent ) ;
static_assert ( UE : : StateTree : : MaxExpressionIndent = = 4 ) ;
switch ( CloseParens )
{
case 1 : return FText : : FromString ( TEXT ( " ) " ) ) ;
case 2 : return FText : : FromString ( TEXT ( " )) " ) ) ;
case 3 : return FText : : FromString ( TEXT ( " ))) " ) ) ;
case 4 : return FText : : FromString ( TEXT ( " )))) " ) ) ;
case 5 : return FText : : FromString ( TEXT ( " ))))) " ) ) ;
}
return FText : : GetEmpty ( ) ;
}
2022-04-05 03:20:57 -04:00
EVisibility SStateTreeViewRow : : GetLinkedStateVisibility ( ) const
{
if ( const UStateTreeState * State = WeakState . Get ( ) )
{
2023-11-30 07:03:20 -05:00
return ( State - > Type = = EStateTreeStateType : : Linked | | State - > Type = = EStateTreeStateType : : LinkedAsset ) ? EVisibility : : Visible : EVisibility : : Collapsed ;
2022-04-05 03:20:57 -04:00
}
return EVisibility : : Collapsed ;
}
2024-04-12 07:21:04 -04:00
bool SStateTreeViewRow : : GetStateWarnings ( FText * OutText ) const
{
bool bHasWarnings = false ;
const UStateTreeState * State = WeakState . Get ( ) ;
if ( ! State )
{
return bHasWarnings ;
}
// Linked States cannot have children.
if ( ( State - > Type = = EStateTreeStateType : : Linked
| | State - > Type = = EStateTreeStateType : : LinkedAsset )
& & State - > Children . Num ( ) > 0 )
{
if ( OutText )
{
* OutText = LOCTEXT ( " LinkedStateChildWarning " , " Linked State cannot have child states, because the state selection will enter to the linked state on activation. " ) ;
}
bHasWarnings = true ;
}
2024-06-13 22:57:49 -04:00
// Child states should not have any considerations if their parent doesn't use utility
if ( State - > Considerations . Num ( ) ! = 0 )
{
if ( ! State - > Parent
| | ( State - > Parent - > SelectionBehavior ! = EStateTreeStateSelectionBehavior : : TrySelectChildrenWithHighestUtility
& & State - > Parent - > SelectionBehavior ! = EStateTreeStateSelectionBehavior : : TrySelectChildrenBasedOnRelativeUtility ) )
{
if ( OutText )
{
* OutText = LOCTEXT ( " ChildStateUtilityConsiderationWarning " ,
" State has Utility Considerations but they don't have effect. "
" The Utility Considerations are used only when parent State's Selection Behavior is: "
" \" Try Select Children with Highest Utility \" or \" Try Select Children Based on Relative Utility. " ) ;
}
bHasWarnings = true ;
}
}
2024-04-12 07:21:04 -04:00
return bHasWarnings ;
}
2022-04-05 03:20:57 -04:00
FText SStateTreeViewRow : : GetLinkedStateDesc ( ) const
{
const UStateTreeState * State = WeakState . Get ( ) ;
if ( ! State )
{
return FText : : GetEmpty ( ) ;
}
if ( State - > Type = = EStateTreeStateType : : Linked )
{
2022-09-30 11:31:57 -04:00
return FText : : FromName ( State - > LinkedSubtree . Name ) ;
2022-04-05 03:20:57 -04:00
}
2023-11-30 07:03:20 -05:00
else if ( State - > Type = = EStateTreeStateType : : LinkedAsset )
{
2023-12-04 03:46:59 -05:00
return FText : : FromString ( GetNameSafe ( State - > LinkedAsset . Get ( ) ) ) ;
2023-11-30 07:03:20 -05:00
}
2022-04-05 03:20:57 -04:00
return FText : : GetEmpty ( ) ;
}
2024-04-12 07:21:04 -04:00
EVisibility SStateTreeViewRow : : GetWarningsVisibility ( ) const
{
return GetStateWarnings ( nullptr ) ? EVisibility : : Visible : EVisibility : : Collapsed ;
}
FText SStateTreeViewRow : : GetWarningsTooltipText ( ) const
{
FText Warnings = FText : : GetEmpty ( ) ;
GetStateWarnings ( & Warnings ) ;
return Warnings ;
}
2022-09-01 09:06:53 -04:00
bool SStateTreeViewRow : : HasParentTransitionForTrigger ( const UStateTreeState & State , const EStateTreeTransitionTrigger Trigger ) const
2021-09-28 13:33:17 -04:00
{
2022-09-01 09:06:53 -04:00
EStateTreeTransitionTrigger CombinedTrigger = EStateTreeTransitionTrigger : : None ;
2021-09-28 13:33:17 -04:00
for ( const UStateTreeState * ParentState = State . Parent ; ParentState ! = nullptr ; ParentState = ParentState - > Parent )
{
2021-10-21 04:08:20 -04:00
for ( const FStateTreeTransition & Transition : ParentState - > Transitions )
2021-09-28 13:33:17 -04:00
{
2022-09-01 09:06:53 -04:00
CombinedTrigger | = Transition . Trigger ;
2021-09-28 13:33:17 -04:00
}
}
2022-09-01 09:06:53 -04:00
return EnumHasAllFlags ( CombinedTrigger , Trigger ) ;
2021-09-28 13:33:17 -04:00
}
2024-08-01 05:38:41 -04:00
FText SStateTreeViewRow : : GetLinkTooltip ( const FStateTreeStateLink & Link , const FGuid NodeID ) const
2023-06-14 06:17:56 -04:00
{
2024-08-01 05:38:41 -04:00
if ( const UStateTreeState * State = WeakState . Get ( ) )
2023-06-14 06:17:56 -04:00
{
2024-08-01 05:38:41 -04:00
const int32 TaskIndex = State - > Tasks . IndexOfByPredicate ( [ & NodeID ] ( const FStateTreeEditorNode & Node )
{
return Node . ID = = NodeID ;
} ) ;
if ( TaskIndex ! = INDEX_NONE )
{
return FText : : Format ( LOCTEXT ( " TaskTransitionDesc " , " Task {0} transitions to {1} " ) ,
FText : : FromName ( State - > Tasks [ TaskIndex ] . GetName ( ) ) ,
UE : : StateTree : : Editor : : GetStateLinkDesc ( WeakEditorData . Get ( ) , Link , EStateTreeNodeFormatting : : Text , /*bShowStatePath*/ true ) ) ;
}
2023-06-14 06:17:56 -04:00
2024-08-01 05:38:41 -04:00
if ( State - > SingleTask . ID = = NodeID )
{
return FText : : Format ( LOCTEXT ( " TaskTransitionDesc " , " Task {0} transitions to {1} " ) ,
FText : : FromName ( State - > SingleTask . GetName ( ) ) ,
UE : : StateTree : : Editor : : GetStateLinkDesc ( WeakEditorData . Get ( ) , Link , EStateTreeNodeFormatting : : Text , /*bShowStatePath*/ true ) ) ;
}
const int32 TransitionIndex = State - > Transitions . IndexOfByPredicate ( [ & NodeID ] ( const FStateTreeTransition & Transition )
{
return Transition . ID = = NodeID ;
} ) ;
if ( TransitionIndex ! = INDEX_NONE )
{
return UE : : StateTree : : Editor : : GetTransitionDesc ( WeakEditorData . Get ( ) , State - > Transitions [ TransitionIndex ] , EStateTreeNodeFormatting : : Text , /*bShowStatePath*/ true ) ;
}
}
2023-06-14 06:17:56 -04:00
return FText : : GetEmpty ( ) ;
} ;
2024-04-11 04:14:59 -04:00
bool SStateTreeViewRow : : IsLeafState ( ) const
{
const UStateTreeState * State = WeakState . Get ( ) ;
return State
& & State - > Children . Num ( ) = = 0
& & ! IsRootState ( )
& & ( State - > Type = = EStateTreeStateType : : State
| | State - > Type = = EStateTreeStateType : : Linked
| | State - > Type = = EStateTreeStateType : : LinkedAsset ) ;
}
2024-08-01 05:38:41 -04:00
TSharedRef < SWidget > SStateTreeViewRow : : MakeTransitionWidgets ( const EStateTreeTransitionTrigger Trigger , const FTransitionDescFilterOptions FilterOptions )
2021-09-28 13:33:17 -04:00
{
2024-04-05 03:37:02 -04:00
const UStateTreeEditorData * TreeEditorData = WeakEditorData . Get ( ) ;
2024-08-01 05:38:41 -04:00
const UStateTreeState * State = WeakState . Get ( ) ;
2023-06-20 13:49:25 -04:00
2024-08-01 05:38:41 -04:00
if ( ! TreeEditorData | | ! State )
{
return SNullWidget : : NullWidget ;
}
struct FItem
{
FItem ( ) = default ;
FItem ( const FStateTreeStateLink & InLink , const FGuid InNodeID )
: Link ( InLink )
, NodeID ( InNodeID )
{
}
FItem ( const FText & InDesc , const FText & InTooltip )
: Desc ( InDesc )
, Tooltip ( InTooltip )
{
}
FText Desc ;
FText Tooltip ;
FStateTreeStateLink Link ;
FGuid NodeID ;
} ;
TArray < FItem > DescItems ;
for ( const FStateTreeTransition & Transition : State - > Transitions )
2021-09-28 13:33:17 -04:00
{
2023-06-20 13:49:25 -04:00
// Apply filter for enabled/disabled transitions
if ( ( FilterOptions . Enabled = = ETransitionDescRequirement : : RequiredTrue & & Transition . bTransitionEnabled = = false )
| | ( FilterOptions . Enabled = = ETransitionDescRequirement : : RequiredFalse & & Transition . bTransitionEnabled ) )
{
continue ;
}
2024-05-02 11:47:26 -04:00
# if WITH_STATETREE_TRACE_DEBUGGER
2023-06-20 13:49:25 -04:00
// Apply filter for transitions with/without breakpoint
const bool bHasBreakpoint = TreeEditorData ! = nullptr & & TreeEditorData - > HasBreakpoint ( Transition . ID , EStateTreeBreakpointType : : OnTransition ) ;
if ( ( FilterOptions . WithBreakpoint = = ETransitionDescRequirement : : RequiredTrue & & bHasBreakpoint = = false )
| | ( FilterOptions . WithBreakpoint = = ETransitionDescRequirement : : RequiredFalse & & bHasBreakpoint ) )
{
continue ;
}
2024-05-02 11:47:26 -04:00
# endif // WITH_STATETREE_TRACE_DEBUGGER
2023-06-20 13:49:25 -04:00
const bool bMatch = FilterOptions . bUseMask ? EnumHasAnyFlags ( Transition . Trigger , Trigger ) : Transition . Trigger = = Trigger ;
2022-09-01 09:06:53 -04:00
if ( bMatch )
2021-09-28 13:33:17 -04:00
{
2024-08-01 05:38:41 -04:00
DescItems . Emplace ( Transition . State , Transition . ID ) ;
2021-09-28 13:33:17 -04:00
}
}
2023-06-14 06:17:56 -04:00
// Find states from transition tasks
if ( EnumHasAnyFlags ( Trigger , EStateTreeTransitionTrigger : : OnTick | EStateTreeTransitionTrigger : : OnEvent ) )
{
2024-08-01 05:38:41 -04:00
auto AddLinksFromStruct = [ & DescItems , TreeEditorData ] ( FStateTreeDataView Struct , const FGuid NodeID )
2023-06-14 06:17:56 -04:00
{
if ( ! Struct . IsValid ( ) )
{
return ;
}
for ( TPropertyValueIterator < FStructProperty > It ( Struct . GetStruct ( ) , Struct . GetMemory ( ) ) ; It ; + + It )
{
const UScriptStruct * StructType = It . Key ( ) - > Struct ;
if ( StructType = = TBaseStructure < FStateTreeStateLink > : : Get ( ) )
{
const FStateTreeStateLink & Link = * static_cast < const FStateTreeStateLink * > ( It . Value ( ) ) ;
if ( Link . LinkType ! = EStateTreeTransitionType : : None )
{
2024-08-01 05:38:41 -04:00
DescItems . Emplace ( Link , NodeID ) ;
2023-06-14 06:17:56 -04:00
}
}
}
} ;
2024-08-01 05:38:41 -04:00
for ( const FStateTreeEditorNode & Task : State - > Tasks )
2023-06-14 06:17:56 -04:00
{
2024-08-01 05:38:41 -04:00
AddLinksFromStruct ( FStateTreeDataView ( Task . Node . GetScriptStruct ( ) , const_cast < uint8 * > ( Task . Node . GetMemory ( ) ) ) , Task . ID ) ;
AddLinksFromStruct ( Task . GetInstance ( ) , Task . ID ) ;
2023-06-14 06:17:56 -04:00
}
2024-08-01 05:38:41 -04:00
AddLinksFromStruct ( FStateTreeDataView ( State - > SingleTask . Node . GetScriptStruct ( ) , const_cast < uint8 * > ( State - > SingleTask . Node . GetMemory ( ) ) ) , State - > SingleTask . ID ) ;
AddLinksFromStruct ( State - > SingleTask . GetInstance ( ) , State - > SingleTask . ID ) ;
2023-06-14 06:17:56 -04:00
}
2024-04-11 04:14:59 -04:00
if ( IsLeafState ( )
2021-09-28 13:33:17 -04:00
& & DescItems . Num ( ) = = 0
2022-09-01 09:06:53 -04:00
& & EnumHasAnyFlags ( Trigger , EStateTreeTransitionTrigger : : OnStateCompleted ) )
2021-09-28 13:33:17 -04:00
{
2024-08-01 05:38:41 -04:00
if ( HasParentTransitionForTrigger ( * State , Trigger ) )
2021-09-28 13:33:17 -04:00
{
2024-08-01 05:38:41 -04:00
DescItems . Emplace (
LOCTEXT ( " TransitionActionHandleInParentRich " , " <i>Parent</> " ) ,
LOCTEXT ( " TransitionActionHandleInParent " , " Handle transition in parent State " )
) ;
2021-09-28 13:33:17 -04:00
}
else
{
2024-08-01 05:38:41 -04:00
DescItems . Emplace (
2024-08-09 09:44:02 -04:00
LOCTEXT ( " TransitionActionRootRich " , " <i>Root</> " ) ,
2024-08-01 05:38:41 -04:00
LOCTEXT ( " TransitionActionRoot " , " Transition to Root State. " )
) ;
2021-09-28 13:33:17 -04:00
}
}
2024-08-01 05:38:41 -04:00
TSharedRef < SHorizontalBox > TransitionContainer = SNew ( SHorizontalBox ) ;
auto IsTransitionEnabledFunc = [ WeakState = WeakState ]
{
const UStateTreeState * State = WeakState . Get ( ) ;
return State & & State - > bEnabled ;
} ;
for ( int32 Index = 0 ; Index < DescItems . Num ( ) ; Index + + )
{
const FItem & Item = DescItems [ Index ] ;
if ( Index > 0 )
{
TransitionContainer - > AddSlot ( )
. AutoWidth ( )
. VAlign ( VAlign_Center )
[
SNew ( STextBlock )
. Text ( FText : : FromString ( TEXT ( " , " ) ) )
. TextStyle ( & FStateTreeEditorStyle : : Get ( ) . GetWidgetStyle < FTextBlockStyle > ( " Transition.Subdued " ) )
] ;
}
TransitionContainer - > AddSlot ( )
. AutoWidth ( )
. VAlign ( VAlign_Center )
[
SNew ( SButton )
. ButtonStyle ( FAppStyle : : Get ( ) , " SimpleButton " )
. ContentPadding ( FMargin ( 0 , 0 ) )
. OnClicked_Lambda ( [ StateTreeViewModel = StateTreeViewModel , WeakState = WeakState , Item ] ( )
{
if ( StateTreeViewModel )
{
StateTreeViewModel - > BringNodeToFocus ( WeakState . Get ( ) , Item . NodeID ) ;
}
return FReply : : Handled ( ) ;
} )
[
SNew ( SBorder )
. VAlign ( VAlign_Center )
. BorderImage ( FAppStyle : : GetNoBrush ( ) )
. Padding ( 0 )
. IsEnabled_Lambda ( IsTransitionEnabledFunc )
[
SNew ( SRichTextBlock )
. Text_Lambda ( [ WeakEditorData = WeakEditorData , Item ] ( )
{
if ( ! Item . Desc . IsEmpty ( ) )
{
return Item . Desc ;
}
return UE : : StateTree : : Editor : : GetStateLinkDesc ( WeakEditorData . Get ( ) , Item . Link , EStateTreeNodeFormatting : : RichText ) ;
} )
. ToolTipText_Lambda ( [ this , Item ] ( )
{
if ( ! Item . Tooltip . IsEmpty ( ) )
{
return Item . Tooltip ;
}
return GetLinkTooltip ( Item . Link , Item . NodeID ) ;
} )
. TextStyle ( & FStateTreeEditorStyle : : Get ( ) . GetWidgetStyle < FTextBlockStyle > ( " Transition.Normal " ) )
+ SRichTextBlock : : Decorator ( FTextStyleDecorator : : Create ( TEXT ( " " ) , FStateTreeEditorStyle : : Get ( ) . GetWidgetStyle < FTextBlockStyle > ( " Transition.Normal " ) ) )
+ SRichTextBlock : : Decorator ( FTextStyleDecorator : : Create ( TEXT ( " b " ) , FStateTreeEditorStyle : : Get ( ) . GetWidgetStyle < FTextBlockStyle > ( " Transition.Bold " ) ) )
+ SRichTextBlock : : Decorator ( FTextStyleDecorator : : Create ( TEXT ( " i " ) , FStateTreeEditorStyle : : Get ( ) . GetWidgetStyle < FTextBlockStyle > ( " Transition.Italic " ) ) )
+ SRichTextBlock : : Decorator ( FTextStyleDecorator : : Create ( TEXT ( " s " ) , FStateTreeEditorStyle : : Get ( ) . GetWidgetStyle < FTextBlockStyle > ( " Transition.Subdued " ) ) )
]
]
] ;
}
2021-09-28 13:33:17 -04:00
2024-08-01 05:38:41 -04:00
return TransitionContainer ;
2021-09-28 13:33:17 -04:00
}
2024-08-01 05:38:41 -04:00
FText SStateTreeViewRow : : GetTransitionsDesc ( const EStateTreeTransitionTrigger Trigger , const FTransitionDescFilterOptions FilterOptions ) const
2021-09-28 13:33:17 -04:00
{
2024-08-01 05:38:41 -04:00
const UStateTreeState * State = WeakState . Get ( ) ;
2024-04-05 03:37:02 -04:00
const UStateTreeEditorData * EditorData = WeakEditorData . Get ( ) ;
2024-08-01 05:38:41 -04:00
if ( ! State | | ! EditorData )
{
return FText : : GetEmpty ( ) ;
}
TArray < FText > DescItems ;
for ( const FStateTreeTransition & Transition : State - > Transitions )
2021-09-28 13:33:17 -04:00
{
2023-06-20 13:49:25 -04:00
// Apply filter for enabled/disabled transitions
if ( ( FilterOptions . Enabled = = ETransitionDescRequirement : : RequiredTrue & & Transition . bTransitionEnabled = = false )
| | ( FilterOptions . Enabled = = ETransitionDescRequirement : : RequiredFalse & & Transition . bTransitionEnabled ) )
{
continue ;
}
2024-08-01 05:38:41 -04:00
# if WITH_STATETREE_TRACE_DEBUGGER
// Apply filter for transitions with/without breakpoint
const bool bHasBreakpoint = EditorData - > HasBreakpoint ( Transition . ID , EStateTreeBreakpointType : : OnTransition ) ;
if ( ( FilterOptions . WithBreakpoint = = ETransitionDescRequirement : : RequiredTrue & & bHasBreakpoint = = false )
| | ( FilterOptions . WithBreakpoint = = ETransitionDescRequirement : : RequiredFalse & & bHasBreakpoint ) )
{
continue ;
}
# endif // WITH_STATETREE_TRACE_DEBUGGER
const bool bMatch = FilterOptions . bUseMask ? EnumHasAnyFlags ( Transition . Trigger , Trigger ) : Transition . Trigger = = Trigger ;
if ( bMatch )
{
DescItems . Add ( UE : : StateTree : : Editor : : GetStateLinkDesc ( EditorData , Transition . State , EStateTreeNodeFormatting : : RichText ) ) ;
}
}
// Find states from transition tasks
if ( EnumHasAnyFlags ( Trigger , EStateTreeTransitionTrigger : : OnTick | EStateTreeTransitionTrigger : : OnEvent ) )
{
auto AddLinksFromStruct = [ EditorData , & DescItems ] ( FStateTreeDataView Struct )
{
if ( ! Struct . IsValid ( ) )
{
return ;
}
for ( TPropertyValueIterator < FStructProperty > It ( Struct . GetStruct ( ) , Struct . GetMemory ( ) ) ; It ; + + It )
{
const UScriptStruct * StructType = It . Key ( ) - > Struct ;
if ( StructType = = TBaseStructure < FStateTreeStateLink > : : Get ( ) )
{
const FStateTreeStateLink & Link = * static_cast < const FStateTreeStateLink * > ( It . Value ( ) ) ;
if ( Link . LinkType ! = EStateTreeTransitionType : : None )
{
DescItems . Add ( UE : : StateTree : : Editor : : GetStateLinkDesc ( EditorData , Link , EStateTreeNodeFormatting : : RichText ) ) ;
}
}
}
} ;
for ( const FStateTreeEditorNode & Task : State - > Tasks )
{
AddLinksFromStruct ( FStateTreeDataView ( Task . Node . GetScriptStruct ( ) , const_cast < uint8 * > ( Task . Node . GetMemory ( ) ) ) ) ;
AddLinksFromStruct ( Task . GetInstance ( ) ) ;
}
AddLinksFromStruct ( FStateTreeDataView ( State - > SingleTask . Node . GetScriptStruct ( ) , const_cast < uint8 * > ( State - > SingleTask . Node . GetMemory ( ) ) ) ) ;
AddLinksFromStruct ( State - > SingleTask . GetInstance ( ) ) ;
}
if ( IsLeafState ( )
& & DescItems . Num ( ) = = 0
& & EnumHasAnyFlags ( Trigger , EStateTreeTransitionTrigger : : OnStateCompleted ) )
{
if ( HasParentTransitionForTrigger ( * State , Trigger ) )
{
DescItems . Add ( LOCTEXT ( " TransitionActionHandleInParentRich " , " <i>Parent</> " ) ) ;
}
else
{
DescItems . Add ( LOCTEXT ( " TransitionActionRootRich " , " <i>Root</> " ) ) ;
}
}
return FText : : Join ( FText : : FromString ( TEXT ( " , " ) ) , DescItems ) ;
}
const FSlateBrush * SStateTreeViewRow : : GetTransitionsIcon ( const EStateTreeTransitionTrigger Trigger ) const
{
const UStateTreeState * State = WeakState . Get ( ) ;
if ( ! State )
{
return nullptr ;
}
if ( EnumHasAnyFlags ( Trigger , EStateTreeTransitionTrigger : : OnTick | EStateTreeTransitionTrigger : : OnEvent ) )
{
return FStateTreeEditorStyle : : Get ( ) . GetBrush ( " StateTreeEditor.Transition.Goto " ) ;
}
enum EIconType
{
IconNone = 0 ,
IconGoto = 1 < < 0 ,
IconNext = 1 < < 1 ,
IconParent = 1 < < 2 ,
} ;
uint8 IconType = IconNone ;
for ( const FStateTreeTransition & Transition : State - > Transitions )
{
// Apply filter for enabled/disabled transitions
/* if ((FilterOptions.Enabled == ETransitionDescRequirement::RequiredTrue && Transition.bTransitionEnabled == false)
| | ( FilterOptions . Enabled = = ETransitionDescRequirement : : RequiredFalse & & Transition . bTransitionEnabled ) )
{
continue ;
} */
/*
2024-05-02 11:47:26 -04:00
# if WITH_STATETREE_TRACE_DEBUGGER
2023-06-20 13:49:25 -04:00
// Apply filter for transitions with/without breakpoint
2024-04-05 03:37:02 -04:00
const bool bHasBreakpoint = EditorData ! = nullptr & & EditorData - > HasBreakpoint ( Transition . ID , EStateTreeBreakpointType : : OnTransition ) ;
2023-06-20 13:49:25 -04:00
if ( ( FilterOptions . WithBreakpoint = = ETransitionDescRequirement : : RequiredTrue & & bHasBreakpoint = = false )
| | ( FilterOptions . WithBreakpoint = = ETransitionDescRequirement : : RequiredFalse & & bHasBreakpoint ) )
{
continue ;
}
2024-05-02 11:47:26 -04:00
# endif // WITH_STATETREE_TRACE_DEBUGGER
2024-08-01 05:38:41 -04:00
*/
2023-06-20 13:49:25 -04:00
2021-09-28 13:33:17 -04:00
// The icons here depict "transition direction", not the type specifically.
2024-08-01 05:38:41 -04:00
const bool bMatch = /*FilterOptions.bUseMask ? EnumHasAnyFlags(Transition.Trigger, Trigger) :*/ Transition . Trigger = = Trigger ;
2022-09-01 09:06:53 -04:00
if ( bMatch )
2021-09-28 13:33:17 -04:00
{
2023-01-23 12:48:04 -05:00
switch ( Transition . State . LinkType )
2021-09-28 13:33:17 -04:00
{
2023-01-23 12:48:04 -05:00
case EStateTreeTransitionType : : None :
2024-04-11 04:14:59 -04:00
IconType | = IconGoto ;
2021-09-28 13:33:17 -04:00
break ;
case EStateTreeTransitionType : : Succeeded :
2024-04-11 04:14:59 -04:00
IconType | = IconGoto ;
2021-09-28 13:33:17 -04:00
break ;
case EStateTreeTransitionType : : Failed :
2024-04-11 04:14:59 -04:00
IconType | = IconGoto ;
2021-09-28 13:33:17 -04:00
break ;
case EStateTreeTransitionType : : NextState :
2023-10-17 16:15:53 -04:00
case EStateTreeTransitionType : : NextSelectableState :
2024-04-11 04:14:59 -04:00
IconType | = IconNext ;
2021-09-28 13:33:17 -04:00
break ;
case EStateTreeTransitionType : : GotoState :
2024-04-11 04:14:59 -04:00
IconType | = IconGoto ;
2021-09-28 13:33:17 -04:00
break ;
default :
ensureMsgf ( false , TEXT ( " Unhandled transition type. " ) ) ;
break ;
}
}
}
if ( FMath : : CountBits ( static_cast < uint64 > ( IconType ) ) > 1 )
{
// Prune down to just one icon.
2024-04-11 04:14:59 -04:00
IconType = IconGoto ;
2021-09-28 13:33:17 -04:00
}
2024-04-11 04:14:59 -04:00
if ( IsLeafState ( )
2023-03-14 13:35:46 -04:00
& & IconType = = IconNone
& & EnumHasAnyFlags ( Trigger , EStateTreeTransitionTrigger : : OnStateCompleted ) )
2021-09-28 13:33:17 -04:00
{
2023-12-14 02:55:56 -05:00
// Transition is handled on parent state, or implicit Root.
2024-04-11 04:14:59 -04:00
IconType = IconParent ;
2021-09-28 13:33:17 -04:00
}
2024-04-01 18:02:13 -04:00
switch ( IconType )
2021-09-28 13:33:17 -04:00
{
2024-04-11 04:14:59 -04:00
case IconGoto :
return FStateTreeEditorStyle : : Get ( ) . GetBrush ( " StateTreeEditor.Transition.Goto " ) ;
case IconNext :
return FStateTreeEditorStyle : : Get ( ) . GetBrush ( " StateTreeEditor.Transition.Next " ) ;
case IconParent :
return FStateTreeEditorStyle : : Get ( ) . GetBrush ( " StateTreeEditor.Transition.Parent " ) ;
2024-04-01 18:02:13 -04:00
default :
2024-04-11 04:14:59 -04:00
break ;
2024-03-25 11:46:14 -04:00
}
2024-04-11 04:14:59 -04:00
return nullptr ;
2021-09-28 13:33:17 -04:00
}
2024-08-01 05:38:41 -04:00
EVisibility SStateTreeViewRow : : GetTransitionsVisibility ( const EStateTreeTransitionTrigger Trigger ) const
2021-09-28 13:33:17 -04:00
{
2024-08-01 05:38:41 -04:00
const UStateTreeState * State = WeakState . Get ( ) ;
if ( ! State )
{
return EVisibility : : Collapsed ;
}
2023-05-08 13:32:14 -04:00
// Handle completed, succeeded and failed transitions.
2022-09-05 09:08:59 -04:00
if ( EnumHasAnyFlags ( Trigger , EStateTreeTransitionTrigger : : OnStateCompleted ) )
2022-09-01 09:06:53 -04:00
{
2022-09-05 09:08:59 -04:00
EStateTreeTransitionTrigger HandledTriggers = EStateTreeTransitionTrigger : : None ;
bool bExactMatch = false ;
2024-08-01 05:38:41 -04:00
for ( const FStateTreeTransition & Transition : State - > Transitions )
2022-09-01 09:06:53 -04:00
{
2023-06-20 13:49:25 -04:00
// Skip disabled transitions
if ( Transition . bTransitionEnabled = = false )
{
continue ;
}
2022-09-05 09:08:59 -04:00
HandledTriggers | = Transition . Trigger ;
bExactMatch | = ( Transition . Trigger = = Trigger ) ;
2023-06-20 13:49:25 -04:00
if ( bExactMatch )
{
break ;
}
2022-09-01 09:06:53 -04:00
}
2021-09-28 13:33:17 -04:00
2022-09-05 09:08:59 -04:00
// Assume that leaf states should have completion transitions.
2024-04-11 04:14:59 -04:00
if ( ! bExactMatch & & IsLeafState ( ) )
2022-09-05 09:08:59 -04:00
{
// Find the missing transition type, note: Completed = Succeeded|Failed.
const EStateTreeTransitionTrigger MissingTriggers = HandledTriggers ^ EStateTreeTransitionTrigger : : OnStateCompleted ;
return MissingTriggers = = Trigger ? EVisibility : : Visible : EVisibility : : Collapsed ;
}
return bExactMatch ? EVisibility : : Visible : EVisibility : : Collapsed ;
}
2023-06-14 06:17:56 -04:00
// Find states from transition tasks
if ( EnumHasAnyFlags ( Trigger , EStateTreeTransitionTrigger : : OnTick | EStateTreeTransitionTrigger : : OnEvent ) )
{
auto HasAnyLinksInStruct = [ ] ( FStateTreeDataView Struct ) - > bool
{
if ( ! Struct . IsValid ( ) )
{
return false ;
}
for ( TPropertyValueIterator < FStructProperty > It ( Struct . GetStruct ( ) , Struct . GetMemory ( ) ) ; It ; + + It )
{
const UScriptStruct * StructType = It . Key ( ) - > Struct ;
if ( StructType = = TBaseStructure < FStateTreeStateLink > : : Get ( ) )
{
const FStateTreeStateLink & Link = * static_cast < const FStateTreeStateLink * > ( It . Value ( ) ) ;
if ( Link . LinkType ! = EStateTreeTransitionType : : None )
{
return true ;
}
}
}
return false ;
} ;
2024-08-01 05:38:41 -04:00
for ( const FStateTreeEditorNode & Task : State - > Tasks )
2023-06-14 06:17:56 -04:00
{
if ( HasAnyLinksInStruct ( FStateTreeDataView ( Task . Node . GetScriptStruct ( ) , const_cast < uint8 * > ( Task . Node . GetMemory ( ) ) ) )
| | HasAnyLinksInStruct ( Task . GetInstance ( ) ) )
{
return EVisibility : : Visible ;
}
}
2024-08-01 05:38:41 -04:00
if ( HasAnyLinksInStruct ( FStateTreeDataView ( State - > SingleTask . Node . GetScriptStruct ( ) , const_cast < uint8 * > ( State - > SingleTask . Node . GetMemory ( ) ) ) )
| | HasAnyLinksInStruct ( State - > SingleTask . GetInstance ( ) ) )
2023-06-14 06:17:56 -04:00
{
return EVisibility : : Visible ;
}
}
2022-09-05 09:08:59 -04:00
// Handle the test
2024-08-01 05:38:41 -04:00
for ( const FStateTreeTransition & Transition : State - > Transitions )
2021-09-28 13:33:17 -04:00
{
2023-06-20 13:49:25 -04:00
// Skip disabled transitions
if ( Transition . bTransitionEnabled = = false )
{
continue ;
}
2022-09-05 09:08:59 -04:00
if ( EnumHasAnyFlags ( Trigger , Transition . Trigger ) )
{
return EVisibility : : Visible ;
}
2021-09-28 13:33:17 -04:00
}
2022-09-05 09:08:59 -04:00
return EVisibility : : Collapsed ;
2021-09-28 13:33:17 -04:00
}
2024-08-01 05:38:41 -04:00
EVisibility SStateTreeViewRow : : GetTransitionsBreakpointVisibility ( const EStateTreeTransitionTrigger Trigger ) const
2023-06-20 13:49:25 -04:00
{
2024-08-01 05:38:41 -04:00
if ( const UStateTreeState * State = WeakState . Get ( ) )
2023-06-20 13:49:25 -04:00
{
2024-08-01 05:38:41 -04:00
# if WITH_STATETREE_TRACE_DEBUGGER
if ( const UStateTreeEditorData * EditorData = WeakEditorData . Get ( ) )
2023-06-20 13:49:25 -04:00
{
2024-08-01 05:38:41 -04:00
for ( const FStateTreeTransition & Transition : State - > Transitions )
2023-06-20 13:49:25 -04:00
{
2024-08-01 05:38:41 -04:00
if ( Transition . bTransitionEnabled & & EnumHasAnyFlags ( Trigger , Transition . Trigger ) )
2023-06-20 13:49:25 -04:00
{
2024-08-01 05:38:41 -04:00
if ( EditorData - > HasBreakpoint ( Transition . ID , EStateTreeBreakpointType : : OnTransition ) )
{
return GetTransitionsVisibility ( Trigger ) ;
}
2023-06-20 13:49:25 -04:00
}
}
}
2024-05-02 11:47:26 -04:00
# endif // WITH_STATETREE_TRACE_DEBUGGER
2024-08-01 05:38:41 -04:00
}
2023-06-20 13:49:25 -04:00
return EVisibility : : Collapsed ;
}
2024-08-01 05:38:41 -04:00
EVisibility SStateTreeViewRow : : GetTransitionDashVisibility ( ) const
2021-09-28 13:33:17 -04:00
{
if ( const UStateTreeState * State = WeakState . Get ( ) )
{
2024-08-01 05:38:41 -04:00
return State - > Transitions . IsEmpty ( ) ? EVisibility : : Collapsed : EVisibility : : Visible ;
2021-09-28 13:33:17 -04:00
}
2024-08-01 05:38:41 -04:00
return EVisibility : : Collapsed ;
2021-09-28 13:33:17 -04:00
}
2022-04-28 03:54:07 -04:00
bool SStateTreeViewRow : : IsRootState ( ) const
2021-09-28 13:33:17 -04:00
{
// Routines can be identified by not having parent state.
const UStateTreeState * State = WeakState . Get ( ) ;
return State ? State - > Parent = = nullptr : false ;
}
2022-09-01 09:06:53 -04:00
bool SStateTreeViewRow : : IsStateSelected ( ) const
2021-09-28 13:33:17 -04:00
{
if ( const UStateTreeState * State = WeakState . Get ( ) )
{
if ( StateTreeViewModel )
{
return StateTreeViewModel - > IsSelected ( State ) ;
}
}
return false ;
}
2022-09-01 09:06:53 -04:00
void SStateTreeViewRow : : HandleNodeLabelTextCommitted ( const FText & NewLabel , ETextCommit : : Type CommitType ) const
2021-09-28 13:33:17 -04:00
{
if ( StateTreeViewModel )
{
if ( UStateTreeState * State = WeakState . Get ( ) )
{
StateTreeViewModel - > RenameState ( State , FName ( * FText : : TrimPrecedingAndTrailing ( NewLabel ) . ToString ( ) ) ) ;
}
}
}
2022-09-01 09:06:53 -04:00
FReply SStateTreeViewRow : : HandleDragDetected ( const FGeometry & , const FPointerEvent & ) const
2021-09-28 13:33:17 -04:00
{
2024-08-01 05:38:41 -04:00
return FReply : : Handled ( ) . BeginDragDrop ( FStateTreeSelectedDragDrop : : New ( StateTreeViewModel ) ) ;
}
void SStateTreeViewRow : : HandleDragLeave ( const FDragDropEvent & DragDropEvent ) const
{
const TSharedPtr < FStateTreeSelectedDragDrop > DragDropOperation = DragDropEvent . GetOperationAs < FStateTreeSelectedDragDrop > ( ) ;
if ( DragDropOperation . IsValid ( ) )
{
DragDropOperation - > SetCanDrop ( false ) ;
}
2021-09-28 13:33:17 -04:00
}
2022-09-30 11:31:57 -04:00
TOptional < EItemDropZone > SStateTreeViewRow : : HandleCanAcceptDrop ( const FDragDropEvent & DragDropEvent , EItemDropZone DropZone , TWeakObjectPtr < UStateTreeState > TargetState ) const
2021-09-28 13:33:17 -04:00
{
2024-08-01 05:38:41 -04:00
const TSharedPtr < FStateTreeSelectedDragDrop > DragDropOperation = DragDropEvent . GetOperationAs < FStateTreeSelectedDragDrop > ( ) ;
2021-09-28 13:33:17 -04:00
if ( DragDropOperation . IsValid ( ) )
{
2024-08-01 05:38:41 -04:00
DragDropOperation - > SetCanDrop ( true ) ;
2021-09-28 13:33:17 -04:00
// Cannot drop on selection or child of selection.
2022-09-30 11:31:57 -04:00
if ( StateTreeViewModel & & StateTreeViewModel - > IsChildOfSelection ( TargetState . Get ( ) ) )
2021-09-28 13:33:17 -04:00
{
2024-08-01 05:38:41 -04:00
DragDropOperation - > SetCanDrop ( false ) ;
2021-09-28 13:33:17 -04:00
return TOptional < EItemDropZone > ( ) ;
}
return DropZone ;
}
return TOptional < EItemDropZone > ( ) ;
}
2022-09-30 11:31:57 -04:00
FReply SStateTreeViewRow : : HandleAcceptDrop ( const FDragDropEvent & DragDropEvent , EItemDropZone DropZone , TWeakObjectPtr < UStateTreeState > TargetState ) const
2021-09-28 13:33:17 -04:00
{
2024-08-01 05:38:41 -04:00
const TSharedPtr < FStateTreeSelectedDragDrop > DragDropOperation = DragDropEvent . GetOperationAs < FStateTreeSelectedDragDrop > ( ) ;
2021-09-28 13:33:17 -04:00
if ( DragDropOperation . IsValid ( ) )
{
if ( StateTreeViewModel )
{
if ( DropZone = = EItemDropZone : : AboveItem )
{
2022-09-30 11:31:57 -04:00
StateTreeViewModel - > MoveSelectedStatesBefore ( TargetState . Get ( ) ) ;
2021-09-28 13:33:17 -04:00
}
else if ( DropZone = = EItemDropZone : : BelowItem )
{
2022-09-30 11:31:57 -04:00
StateTreeViewModel - > MoveSelectedStatesAfter ( TargetState . Get ( ) ) ;
2021-09-28 13:33:17 -04:00
}
else
{
2022-09-30 11:31:57 -04:00
StateTreeViewModel - > MoveSelectedStatesInto ( TargetState . Get ( ) ) ;
2021-09-28 13:33:17 -04:00
}
return FReply : : Handled ( ) ;
}
}
return FReply : : Unhandled ( ) ;
}
# undef LOCTEXT_NAMESPACE