Files
UnrealEngineUWP/Engine/Source/Developer/TaskGraph/Private/SEventsTree.cpp

671 lines
21 KiB
C++
Raw Normal View History

// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
#include "SlateBasics.h"
#include "TaskGraphInterfaces.h"
#include "VisualizerEvents.h"
#include "SEventsTree.h"
#include "SSearchBox.h"
#define LOCTEXT_NAMESPACE "SEventsTree"
FName SEventsTree::NAME_NameColumn = FName(*NSLOCTEXT("TaskGraph", "ColumnName", "Name").ToString());
FName SEventsTree::NAME_DurationColumn = FName( *NSLOCTEXT("TaskGraph", "ColumnDuration", "Duration").ToString() );
void SEventItem::Construct( const FArguments& InArgs, const TSharedRef<STableViewBase>& InOwnerTableView )
{
EventName = InArgs._EventName;
EventDuration = InArgs._EventDuration;
SMultiColumnTableRow< TSharedPtr< FVisualizerEvent > >::Construct( FSuperRowType::FArguments(), InOwnerTableView );
}
BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION
TSharedRef< SWidget > SEventItem::GenerateWidgetForColumn( const FName& ColumnName )
{
if( ColumnName == SEventsTree::NAME_NameColumn )
{
return
SNew(SHorizontalBox)
+SHorizontalBox::Slot()
.AutoWidth()
[
SNew( SExpanderArrow, SharedThis(this) )
]
+SHorizontalBox::Slot()
.AutoWidth()
[
SNew( STextBlock )
.Text( FText::FromString(EventName) )
];
}
else if( ColumnName == SEventsTree::NAME_DurationColumn )
{
return SNew( STextBlock )
.Text( this, &SEventItem::GetDurationText );
}
else
{
return
SNew( STextBlock )
. Text(FText::Format( LOCTEXT("UnsupportedColumnFmt", "Unsupported Column: {0}"), FText::FromName(ColumnName) ) );
}
}
END_SLATE_FUNCTION_BUILD_OPTIMIZATION
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION
void SEventsTree::Construct( const FArguments& InArgs )
{
DurationUnits = EVisualizerTimeUnits::Milliseconds;
ViewMode = EVisualizerViewMode::Hierarchical;
bSuppressSelectionChangedEvent = false;
OnEventSelectionChangedDelegate = InArgs._OnEventSelectionChanged;
ProfileData = InArgs._ProfileData.Get();
// Duration column drop down menu
const bool bInShouldCloseWindowAfterMenuSelection = true;
FMenuBuilder MenuBuilder( bInShouldCloseWindowAfterMenuSelection, NULL );
{
FUIAction Action( FExecuteAction::CreateSP( this, &SEventsTree::SetDurationUnits, EVisualizerTimeUnits::Microseconds ),
FCanExecuteAction(),
FIsActionChecked::CreateSP( this, &SEventsTree::CheckDurationUnits, EVisualizerTimeUnits::Microseconds ) );
MenuBuilder.AddMenuEntry( LOCTEXT("Microseconds", "Microseconds"), FText(), FSlateIcon(), Action, NAME_None, EUserInterfaceActionType::Check );
}
{
FUIAction Action( FExecuteAction::CreateSP( this, &SEventsTree::SetDurationUnits, EVisualizerTimeUnits::Milliseconds ),
FCanExecuteAction(),
FIsActionChecked::CreateSP( this, &SEventsTree::CheckDurationUnits, EVisualizerTimeUnits::Milliseconds ) );
MenuBuilder.AddMenuEntry( LOCTEXT("Milliseconds", "Milliseconds"), FText(), FSlateIcon(), Action, NAME_None, EUserInterfaceActionType::Check );
}
{
FUIAction Action( FExecuteAction::CreateSP( this, &SEventsTree::SetDurationUnits, EVisualizerTimeUnits::Seconds ),
FCanExecuteAction(),
FIsActionChecked::CreateSP( this, &SEventsTree::CheckDurationUnits, EVisualizerTimeUnits::Seconds ) );
MenuBuilder.AddMenuEntry( LOCTEXT("Seconds", "Seconds"), FText(), FSlateIcon(), Action, NAME_None, EUserInterfaceActionType::Check );
}
// Name column drop down menu
FMenuBuilder NameMenuBuilder( bInShouldCloseWindowAfterMenuSelection, NULL );
{
FUIAction Action( FExecuteAction::CreateSP( this, &SEventsTree::SetViewMode, EVisualizerViewMode::Hierarchical ),
FCanExecuteAction(),
FIsActionChecked::CreateSP( this, &SEventsTree::CheckViewMode, EVisualizerViewMode::Hierarchical ) );
NameMenuBuilder.AddMenuEntry( LOCTEXT("Hierarchical", "Hierarchical"), FText(), FSlateIcon(), Action, NAME_None, EUserInterfaceActionType::Check );
}
{
FUIAction Action( FExecuteAction::CreateSP( this, &SEventsTree::SetViewMode, EVisualizerViewMode::Flat ),
FCanExecuteAction(),
FIsActionChecked::CreateSP( this, &SEventsTree::CheckViewMode, EVisualizerViewMode::Flat ) );
NameMenuBuilder.AddMenuEntry( LOCTEXT("Flat", "Flat"), FText(), FSlateIcon(), Action, NAME_None, EUserInterfaceActionType::Check );
}
{
FUIAction Action( FExecuteAction::CreateSP( this, &SEventsTree::SetViewMode, EVisualizerViewMode::Coalesced ),
FCanExecuteAction(),
FIsActionChecked::CreateSP( this, &SEventsTree::CheckViewMode, EVisualizerViewMode::Coalesced ) );
NameMenuBuilder.AddMenuEntry( LOCTEXT("Coalesced", "Coalesced"), FText(), FSlateIcon(), Action, NAME_None, EUserInterfaceActionType::Check );
}
{
FUIAction Action( FExecuteAction::CreateSP( this, &SEventsTree::SetViewMode, EVisualizerViewMode::FlatCoalesced ),
FCanExecuteAction(),
FIsActionChecked::CreateSP( this, &SEventsTree::CheckViewMode, EVisualizerViewMode::FlatCoalesced ) );
NameMenuBuilder.AddMenuEntry( LOCTEXT("FlatCoalesced", "Flat Coalesced"), FText(), FSlateIcon(), Action, NAME_None, EUserInterfaceActionType::Check );
}
this->ChildSlot
[
SNew( SVerticalBox )
+SVerticalBox::Slot().AutoHeight().Padding( 1.0f, 0.0f, 1.0f, 2.0f )
[
SNew( SSearchBox )
.ToolTipText( NSLOCTEXT("TaskGraph", "FilterSearchHint", "Type here to search events.") )
.OnTextChanged( this, &SEventsTree::OnFilterTextChanged )
.OnTextCommitted( this, &SEventsTree::OnFilterTextCommitted )
]
+SVerticalBox::Slot().Padding( 2 ).FillHeight( 1 ).VAlign( VAlign_Fill )
[
SNew( SHorizontalBox )
+SHorizontalBox::Slot().Padding( 2 ).FillWidth( 1 ).HAlign( HAlign_Fill )
[
// List of all events for the selected thread
SAssignNew( EventsListView, STreeView< TSharedPtr< FVisualizerEvent > > )
// List view items are this tall
.ItemHeight( 12 )
// Tell the list view where to get its source data
.TreeItemsSource( &SelectedEventsView )
// When the list view needs to generate a widget for some data item, use this method
.OnGenerateRow( this, &SEventsTree::OnGenerateWidgetForEventsList )
// Given some DataItem, this is how we find out if it has any children and what they are.
.OnGetChildren( this, &SEventsTree::OnGetChildrenForEventsList )
// Selection mode
.SelectionMode( ESelectionMode::Single )
// Selection callback
.OnSelectionChanged( this, &SEventsTree::OnEventSelectionChanged )
.HeaderRow
(
SNew( SHeaderRow )
+ SHeaderRow::Column( NAME_NameColumn )
.DefaultLabel( NSLOCTEXT("TaskGraph", "ColumnName", "Name") )
.SortMode( TAttribute< EColumnSortMode::Type >::Create( TAttribute< EColumnSortMode::Type >::FGetter::CreateSP( this, &SEventsTree::GetColumnSortMode, NAME_NameColumn ) ) )
.OnSort( FOnSortModeChanged::CreateSP( this, &SEventsTree::OnColumnSortModeChanged ) )
.FillWidth( 1.0f )
.MenuContent()
[
NameMenuBuilder.MakeWidget()
]
+ SHeaderRow::Column( NAME_DurationColumn )
.DefaultLabel( this, &SEventsTree::GetDurationColumnTitle )
.SortMode( TAttribute< EColumnSortMode::Type >::Create( TAttribute< EColumnSortMode::Type >::FGetter::CreateSP( this, &SEventsTree::GetColumnSortMode, NAME_DurationColumn ) ) )
.OnSort( FOnSortModeChanged::CreateSP( this, &SEventsTree::OnColumnSortModeChanged ) )
.FixedWidth( 128.0f )
.MenuContent()
[
MenuBuilder.MakeWidget()
]
)
]
]
];
}
END_SLATE_FUNCTION_BUILD_OPTIMIZATION
EColumnSortMode::Type SEventsTree::GetColumnSortMode( const FName ColumnId )
{
if ( SortByColumn != ColumnId )
{
return EColumnSortMode::None;
}
return SortMode;
}
FText SEventsTree::GetDurationColumnTitle() const
{
static const FText Units[] = { NSLOCTEXT("TaskGraph", "microseconds", "microseconds"), NSLOCTEXT("TaskGraph", "milliseconds", "ms"), NSLOCTEXT("TaskGraph", "seconds", "s") };
return FText::Format( NSLOCTEXT("TaskGraph", "ColumnDurationValue", "Duration ({0})"), Units[ DurationUnits ] );
}
void ClearEventsSelection( TArray< TSharedPtr< FVisualizerEvent > >& Events )
{
for( int32 Index = 0; Index < Events.Num(); ++Index )
{
TSharedPtr< FVisualizerEvent > CurrentEvent = Events[ Index ];
CurrentEvent->IsSelected = false;
// Clear recursively
if( CurrentEvent->Children.Num() )
{
ClearEventsSelection( CurrentEvent->Children );
}
}
}
void SEventsTree::OnEventSelectionChanged( TSharedPtr< FVisualizerEvent > Selection, ESelectInfo::Type /*SelectInfo*/ )
{
if( Selection.IsValid() )
{
ClearEventsSelection( SelectedEventsView );
Selection->IsSelected = true;
// Mirror the selection in the source events list
TSharedPtr< FVisualizerEvent > MappedSelection = ViewToEventsMap.FindChecked( Selection );
MappedSelection->IsSelected = true;
if( !bSuppressSelectionChangedEvent )
{
OnEventSelectionChangedDelegate.ExecuteIfBound( MappedSelection );
}
}
else if( !bSuppressSelectionChangedEvent )
{
OnEventSelectionChangedDelegate.ExecuteIfBound( Selection );
}
}
TSharedRef< ITableRow > SEventsTree::OnGenerateWidgetForEventsList( TSharedPtr< FVisualizerEvent > InItem, const TSharedRef<STableViewBase>& OwnerTable )
{
return SNew( SEventItem, OwnerTable )
.EventName( InItem->EventName )
.EventDuration( this, &SEventsTree::GetEventDuration, InItem->DurationMs );
}
double SEventsTree::GetEventDuration( double InDurationMs ) const
{
switch( DurationUnits )
{
case EVisualizerTimeUnits::Microseconds:
return InDurationMs * 1000.0;
case EVisualizerTimeUnits::Milliseconds:
return InDurationMs;
case EVisualizerTimeUnits::Seconds:
return InDurationMs * 0.001;
}
return InDurationMs;
}
void SEventsTree::SetDurationUnits( EVisualizerTimeUnits::Type InUnits )
{
DurationUnits = InUnits;
EventsListView->RequestTreeRefresh();
}
void SEventsTree::SetViewMode( EVisualizerViewMode::Type InMode )
{
ViewMode = InMode;
CreateSelectedEventsView();
SortEventsList();
EventsListView->RequestTreeRefresh();
}
void SEventsTree::OnGetChildrenForEventsList( TSharedPtr<FVisualizerEvent> InItem, TArray<TSharedPtr<FVisualizerEvent> >& OutChildren )
{
OutChildren = InItem->Children;
}
Asset View now supports secondary sorting #UDN: Feature suggestion; Content browser can sort by a second column #branch UE4 #change Added two new images for secondary sort ascending and descending. (Updated styles where needed). Added new enum EColumnSortPriority: currently only lists Primary and Secondary, but can easily accommodate more*. (FOnSortModeChanged was modified to also have the priority as a param, fixedup existing usage). SHeaderRow now also has a SortPriority attribute to specify the SortMode order (Defaults to Primary if unused). Modified TUniquePtr so that assigning one from another worked correctly. (Reviewed by Steve Robb). SAssetView is the only table that has been modified, so far, to take advantage of the secondary sort. SetMajorityAssetType has been updated to correctly filter out all those sorts which are no longer relevant and bump the priority of the remaining sorts to fill in the ægapsÆ made by non-longer-relevant ones. FAssetViewSortManager has been overhauled to take SortPriority into consideration when sortingà Firstly, duplicate comparison structs were removed in favour of single structs which have æascendingÆ as a paramà any remaining duplicate code was removed in favour of an inherited usage. The base struct has an array of æfurther methodsÆ to employ in the result of a tie. Should a tie occur the ænextÆ comparison is done, and so on until itÆs not a tie or we run out of comparisons to perform.* The manager defaults to having no secondary sort, so it relies on the interface thatÆs using it to provide it. Whenever a column is assign the code makes sure that itÆs not already assigned to another column and corrects the order to take this into account. Fixed a bug in FCompareFAssetItemByTagNumericalAscending comparing A with A (instead of B). Various optimizations to the sort to descrease times *The only places æSecondaryÆ is referred to in code is in GetSortingBrush (so it can display the correct icon for the sort), and OnTitleClicked (so it can set to correct sort based on input). The sorting code itself has no concept as to a secondary sort, it can support any number of sorting levels so if in future a tertiary (or more) is added, it is only these two function which should need updating as the sort will automatically accommodate it. reviewed by Thomas.Sarkanen, Bob.Tellez [CL 2119201 by Andrew Brown in Main branch]
2014-06-27 04:30:08 -04:00
void SEventsTree::OnColumnSortModeChanged( const EColumnSortPriority::Type SortPriority, const FName& ColumnId, const EColumnSortMode::Type InSortMode )
{
SortByColumn = ColumnId;
SortMode = InSortMode;
SortEventsList();
}
void SEventsTree::SortEventsList( TArray< TSharedPtr< FVisualizerEvent > >& Events )
{
// Sort taking the current settings into account
if( SortByColumn == NAME_NameColumn )
{
if( SortMode == EColumnSortMode::Ascending )
{
struct FCompareEventsByName
{
FORCEINLINE bool operator()( const TSharedPtr<FVisualizerEvent> A, const TSharedPtr<FVisualizerEvent> B ) const { return A->EventName < B->EventName; }
};
Events.Sort( FCompareEventsByName() );
}
else if( SortMode == EColumnSortMode::Descending )
{
struct FCompareEventsByNameDescending
{
FORCEINLINE bool operator()( const TSharedPtr<FVisualizerEvent> A, const TSharedPtr<FVisualizerEvent> B ) const { return B->EventName < A->EventName; }
};
Events.Sort( FCompareEventsByNameDescending() );
}
}
else if( SortByColumn == NAME_DurationColumn )
{
if( SortMode == EColumnSortMode::Ascending )
{
struct FCompareEventsByDuration
{
FORCEINLINE bool operator()( const TSharedPtr<FVisualizerEvent> A, const TSharedPtr<FVisualizerEvent> B ) const { return A->DurationMs < B->DurationMs; }
};
Events.Sort( FCompareEventsByDuration() );
}
else if( SortMode == EColumnSortMode::Descending )
{
struct FCompareEventsByDurationDescending
{
FORCEINLINE bool operator()( const TSharedPtr<FVisualizerEvent> A, const TSharedPtr<FVisualizerEvent> B ) const { return B->DurationMs < A->DurationMs; }
};
Events.Sort( FCompareEventsByDurationDescending() );
}
}
// Sort recursively
for( int32 Index = 0; Index < Events.Num(); Index++ )
{
if( Events[ Index ]->Children.Num() )
{
SortEventsList( Events[ Index ]->Children );
}
}
}
void SEventsTree::SortEventsList( void )
{
SortEventsList( SelectedEventsView );
EventsListView->RequestTreeRefresh();
RestoreEventSelection( SelectedEventsView );
}
bool SEventsTree::RestoreEventSelection( TArray< TSharedPtr< FVisualizerEvent > >& Events )
{
// Search for the selected event
for( int32 Index = 0; Index < Events.Num(); ++Index )
{
if( Events[ Index ]->IsSelected )
{
// Select it in the tree view widget
EventsListView->ClearSelection();
EventsListView->RequestTreeRefresh();
EventsListView->SetSelection( Events[ Index ] );
EventsListView->RequestScrollIntoView( Events[ Index ] );
return true;
}
// Search recursively
if( RestoreEventSelection( Events[ Index ]->Children ) )
{
return true;
}
}
return false;
}
void SEventsTree::HandleBarGraphSelectionChanged( TSharedPtr< FVisualizerEvent > Selection )
{
if ( Selection.IsValid() )
{
for( int32 EventIndex = 0; EventIndex < SelectedEvents.Num(); EventIndex++ )
{
TSharedPtr<FVisualizerEvent> Event = SelectedEvents[ EventIndex ];
if( Selection->EventName == Event->EventName )
{
HandleBarEventSelectionChanged( SelectedThread->Category, Event );
break;
}
}
}
}
void SEventsTree::HandleBarGraphExpansionChanged( TSharedPtr< FVisualizerEvent > Selection )
{
if ( Selection.IsValid() )
{
// We don't want to trigger selection changed event when the selection change is actually coming from the bar graph
bSuppressSelectionChangedEvent = true;
SelectedThread = Selection;
SelectedEvents = Selection.Get()->Children;
CreateSelectedEventsView();
SortEventsList();
bSuppressSelectionChangedEvent = false;
}
}
void SEventsTree::HandleBarEventSelectionChanged( int32 Thread, TSharedPtr<FVisualizerEvent> Selection )
{
const TSharedPtr< FVisualizerEvent >* MappedViewSelection = ViewToEventsMap.FindKey( Selection );
if( MappedViewSelection )
{
TSharedPtr< FVisualizerEvent > ViewSelection = *MappedViewSelection;
// Clear the current selection
EventsListView->ClearSelection();
EventsListView->RequestTreeRefresh();
// Expand all parents so that it's visible
for( TSharedPtr< FVisualizerEvent > ParentEvent = ViewSelection->ParentEvent; ParentEvent.IsValid(); ParentEvent = ParentEvent->ParentEvent )
{
EventsListView->SetItemExpansion( ParentEvent, true );
}
EventsListView->SetSelection( ViewSelection );
EventsListView->RequestScrollIntoView( ViewSelection );
}
else
{
EventsListView->ClearSelection();
}
}
FString SEventsTree::GetTabTitle() const
{
if ( SelectedThread.IsValid() )
{
return SelectedThread->EventName;
}
else
{
return NSLOCTEXT("TaskGraph", "EventsVisualizerName", "Empty Events List").ToString();
}
}
int32 SEventsTree::CountEvents( TArray< TSharedPtr< FVisualizerEvent > >& Events )
{
int32 Count = Events.Num();
for( int32 Index = 0; Index < Events.Num(); Index++ )
{
Count += CountEvents( Events[ Index ]->Children );
}
return Count;
}
void SEventsTree::CreateSelectedEventsView()
{
const int32 EventsCount = CountEvents( SelectedEvents );
ViewToEventsMap.Empty( EventsCount );
SelectedEventsView.Empty( SelectedEvents.Num() );
// Create the selected events copy based on the current view mode
if( ViewMode == EVisualizerViewMode::Hierarchical )
{
SelectedEventsView.Empty( SelectedEvents.Num() );
for( int32 Index = 0; Index < SelectedEvents.Num(); Index++ )
{
if( FilterEvent( SelectedEvents[ Index ] ) )
{
TSharedPtr< FVisualizerEvent > EventCopy( CreateSelectedEventsViewRecursively( SelectedEvents[ Index ] ) );
if( EventCopy.IsValid() )
{
SelectedEventsView.Add( EventCopy );
}
}
}
}
else if( ViewMode == EVisualizerViewMode::Flat )
{
SelectedEventsView.Empty( EventsCount );
for( int32 Index = 0; Index < SelectedEvents.Num(); Index++ )
{
CreateSelectedEventsViewRecursivelyAndFlatten( SelectedEvents[ Index ] );
}
}
else if( ViewMode == EVisualizerViewMode::Coalesced )
{
SelectedEventsView.Empty( SelectedEvents.Num() );
CreateSelectedEventsViewRecursivelyCoalesced( SelectedEvents, SelectedEventsView, TSharedPtr< FVisualizerEvent >() );
}
else if( ViewMode == EVisualizerViewMode::FlatCoalesced )
{
SelectedEventsView.Empty( EventsCount );
CreateSelectedEventsViewRecursivelyFlatCoalesced( SelectedEvents );
}
}
TSharedPtr< FVisualizerEvent > SEventsTree::CreateSelectedEventsViewRecursively( TSharedPtr< FVisualizerEvent > SourceEvent )
{
TSharedPtr< FVisualizerEvent > EventCopy( new FVisualizerEvent( *SourceEvent ) );
EventCopy->Children.Empty( SourceEvent->Children.Num() );
for( int32 ChildIndex = 0; ChildIndex < SourceEvent->Children.Num(); ChildIndex++ )
{
if( FilterEvent( SourceEvent->Children[ ChildIndex ] ) )
{
TSharedPtr< FVisualizerEvent > ChildCopy = CreateSelectedEventsViewRecursively( SourceEvent->Children[ ChildIndex ] );
if( ChildCopy.IsValid() )
{
ChildCopy->ParentEvent = EventCopy;
EventCopy->Children.Add( ChildCopy );
}
}
}
// Add this event because it's a leaf or has valid children
if( EventCopy->Children.Num() > 0 || SourceEvent->Children.Num() == 0 )
{
ViewToEventsMap.Add( EventCopy, SourceEvent );
}
else
{
EventCopy.Reset();
}
return EventCopy;
}
void SEventsTree::CreateSelectedEventsViewRecursivelyAndFlatten( TSharedPtr< FVisualizerEvent > SourceEvent )
{
// Collect only children and store them directly into SelectedEventsView
if ( FilterEvent( SourceEvent ) && SourceEvent->Children.Num() == 0 )
{
TSharedPtr< FVisualizerEvent > EventCopy( new FVisualizerEvent( *SourceEvent ) );
EventCopy->ParentEvent.Reset();
ViewToEventsMap.Add( EventCopy, SourceEvent );
SelectedEventsView.Add( EventCopy );
}
for( int32 ChildIndex = 0; ChildIndex < SourceEvent->Children.Num(); ChildIndex++ )
{
CreateSelectedEventsViewRecursivelyAndFlatten( SourceEvent->Children[ ChildIndex ] );
}
}
void SEventsTree::CreateSelectedEventsViewRecursivelyCoalesced( TArray< TSharedPtr< FVisualizerEvent > >& SourceEvents, TArray< TSharedPtr< FVisualizerEvent > >& CopiedEvents, TSharedPtr< FVisualizerEvent > InParent )
{
for( int32 SourceIndex = 0; SourceIndex < SourceEvents.Num(); SourceIndex++ )
{
TSharedPtr< FVisualizerEvent > SourceEvent = SourceEvents[ SourceIndex ];
if( FilterEvent( SourceEvent ) )
{
if( SourceEvent->Children.Num() == 0 )
{
// Check if a child with the same name has already been added to the copied event
bool bEventExists = false;
for( int32 CopiedEventIndex = 0; CopiedEventIndex < CopiedEvents.Num(); CopiedEventIndex++ )
{
if( CopiedEvents[ CopiedEventIndex ]->EventName == SourceEvent->EventName )
{
bEventExists = true;
break;
}
}
if( !bEventExists )
{
TSharedPtr< FVisualizerEvent > EventCopy( new FVisualizerEvent( *SourceEvent ) );
EventCopy->ParentEvent = InParent;
ViewToEventsMap.Add( EventCopy, SourceEvent );
CopiedEvents.Add( EventCopy );
// Find other children with the same name and add their time to the copied one
for( int32 OtherIndex = SourceIndex + 1; OtherIndex < SourceEvents.Num(); OtherIndex++ )
{
TSharedPtr< FVisualizerEvent > OtherEvent = SourceEvents[ OtherIndex ];
if( OtherEvent->Children.Num() == 0 && OtherEvent->EventName == SourceEvent->EventName )
{
EventCopy->DurationMs += OtherEvent->DurationMs;
}
}
}
}
else
{
TSharedPtr< FVisualizerEvent > EventCopy( new FVisualizerEvent( *SourceEvent ) );
EventCopy->Children.Empty( SourceEvent->Children.Num() );
EventCopy->ParentEvent = InParent;
CreateSelectedEventsViewRecursivelyCoalesced( SourceEvent->Children, EventCopy->Children, EventCopy );
// Only add this event if its children haven't been filtered
if( EventCopy->Children.Num() )
{
ViewToEventsMap.Add( EventCopy, SourceEvent );
CopiedEvents.Add( EventCopy );
}
}
}
}
}
void SEventsTree::CreateSelectedEventsViewRecursivelyFlatCoalesced( TArray< TSharedPtr< FVisualizerEvent > >& SourceEvents )
{
for( int32 SourceIndex = 0; SourceIndex < SourceEvents.Num(); SourceIndex++ )
{
TSharedPtr< FVisualizerEvent > SourceEvent = SourceEvents[ SourceIndex ];
if( FilterEvent( SourceEvent ) )
{
if( SourceEvent->Children.Num() == 0 )
{
// Check if a child with the same name has already been added to the copied event
bool bEventExists = false;
for( int32 CopiedEventIndex = 0; CopiedEventIndex < SelectedEventsView.Num(); CopiedEventIndex++ )
{
if( SelectedEventsView[ CopiedEventIndex ]->EventName == SourceEvent->EventName )
{
bEventExists = true;
break;
}
}
if( !bEventExists )
{
TSharedPtr< FVisualizerEvent > EventCopy( new FVisualizerEvent( *SourceEvent ) );
EventCopy->ParentEvent.Reset();
ViewToEventsMap.Add( EventCopy, SourceEvent );
SelectedEventsView.Add( EventCopy );
// Find other children with the same name and add their time to the copied one
for( int32 OtherIndex = SourceIndex + 1; OtherIndex < SourceEvents.Num(); OtherIndex++ )
{
TSharedPtr< FVisualizerEvent > OtherEvent = SourceEvents[ OtherIndex ];
if( OtherEvent->Children.Num() == 0 && OtherEvent->EventName == SourceEvent->EventName )
{
EventCopy->DurationMs += OtherEvent->DurationMs;
}
}
}
}
else
{
CreateSelectedEventsViewRecursivelyFlatCoalesced( SourceEvent->Children );
}
}
}
}
void SEventsTree::OnFilterTextChanged( const FText& InFilterText )
{
FilterText = InFilterText.ToString();
CreateSelectedEventsView();
EventsListView->RequestTreeRefresh();
}
void SEventsTree::OnFilterTextCommitted( const FText& InFilterText, ETextCommit::Type /*CommitInfo*/ )
{
}
#undef LOCTEXT_NAMESPACE