Files
UnrealEngineUWP/Engine/Source/Developer/LogVisualizer/Private/SLogVisualizer.cpp

2683 lines
79 KiB
C++
Raw Normal View History

// Copyright 1998-2014 Epic Games, Inc. All Rights Reserved.
#include "LogVisualizerPCH.h"
#include "SLogBar.h"
#include "Debug/LogVisualizerCameraController.h"
#include "Debug/ReporterGraph.h"
#include "MainFrame.h"
#include "DesktopPlatformModule.h"
#include "Json.h"
#include "Editor/UnrealEd/Classes/Editor/EditorEngine.h"
Merging using UE4-Fortnite-To-UE4 up to CL 2082758 Includes following engine CLs: CL 2080462: Added verbosity selection to category filters in Log Visualizer window CL 2081939: Fixed crash in Log Visualizer and missing entry on timeline with log containing only 2 entries. CL 2082118: Fixes and improovements for VisLogs - fixed logs visualization for logs with only one entry (Log Visualizer window) - fixed logs spam about missing json field (Log Visualizer window) - fixed crash with categories in Log Visualization window - added category and verbosity serialization for vislog shape elements (vlog files) CL 2080253: Added categories to VisLog shapes CL 2081762: Fixes to Log Visualizer. Logs without any log lines but with geometry elements are set on timeline properly. CL 2081859: Added double click to Log Visualizer action, to move editor camera to view current log location CL 2080159: Gameply Tag Pin now only allows single select #TTP 335383 - Editor: GameplayTag Pin should only allow a single selection #proj UE4 #change Removes all other tags from the correct container when in single select mode, was a missed variable change from a previous TTP CL 2081306: Made changes to navigation filters that allow for usage of virtual verstion dtQueryFilter #UE4 The scary part here is that having a dtQueryFilter contan a vftable was messing up FRecastQueryFilter's vftable it was getting from INavigationQueryFilterInterface. Reversing order of parent clas declaration of FRecastQueryFilter fixed the issue, but it's scary and looks like a compiler issue. [CL 2088758 by Billy Bramer in Main branch]
2014-05-29 17:46:51 -04:00
#if WITH_EDITOR
# include "Editor/UnrealEd/Public/EditorComponents.h"
# include "Editor/UnrealEd/Public/EditorReimportHandler.h"
# include "Editor/UnrealEd/Public/TexAlignTools.h"
# include "Editor/UnrealEd/Public/TickableEditorObject.h"
# include "UnrealEdClasses.h"
# include "Editor/UnrealEd/Public/Editor.h"
# include "Editor/UnrealEd/Public/EditorViewportClient.h"
#endif
#include "GameplayDebuggingComponent.h"
#include "LogVisualizerModule.h"
#include "SFilterList.h"
#if ENABLE_VISUAL_LOG
#define LOCTEXT_NAMESPACE "SLogVisualizer"
const FName SLogVisualizer::NAME_LogName = TEXT("LogName");
const FName SLogVisualizer::NAME_StartTime = TEXT("StartTime");
const FName SLogVisualizer::NAME_EndTime = TEXT("EndTime");
const FName SLogVisualizer::NAME_LogTimeSpan = TEXT("LogTimeSpan");
namespace LogVisualizer
{
static const FString LogFileExtensionPure = TEXT("vlog");
static const FString LogFileDescription = LOCTEXT("FileTypeDescription", "Visual Log File").ToString();
static const FString LogFileExtension = FString::Printf(TEXT("*.%s"), *LogFileExtensionPure);
static const FString FileTypes = FString::Printf( TEXT("%s (%s)|%s"), *LogFileDescription, *LogFileExtension, *LogFileExtension );
}
FColor SLogVisualizer::ColorPalette[] = {
FColor(0xff00A480),
FColorList::Aquamarine,
FColorList::Cyan,
FColorList::Brown,
FColorList::Green,
FColorList::Orange,
FColorList::Magenta,
FColorList::BrightGold,
FColorList::NeonBlue,
FColorList::MediumSlateBlue,
FColorList::SpicyPink,
FColorList::SpringGreen,
FColorList::SteelBlue,
FColorList::SummerSky,
FColorList::Violet,
FColorList::VioletRed,
FColorList::YellowGreen,
FColor(0xff62E200),
FColor(0xff1F7B67),
FColor(0xff62AA2A),
FColor(0xff70227E),
FColor(0xff006B53),
FColor(0xff409300),
FColor(0xff5D016D),
FColor(0xff34D2AF),
FColor(0xff8BF13C),
FColor(0xffBC38D3),
FColor(0xff5ED2B8),
FColor(0xffA6F16C),
FColor(0xffC262D3),
FColor(0xff0F4FA8),
FColor(0xff00AE68),
FColor(0xffDC0055),
FColor(0xff284C7E),
FColor(0xff21825B),
FColor(0xffA52959),
FColor(0xff05316D),
FColor(0xff007143),
FColor(0xff8F0037),
FColor(0xff4380D3),
FColor(0xff36D695),
FColor(0xffEE3B80),
FColor(0xff6996D3),
FColor(0xff60D6A7),
FColor(0xffEE6B9E)
};
template <typename ItemType>
class SLogListView : public SListView<ItemType>
{
public:
virtual FReply OnMouseWheel(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override
{
if (!MouseEvent.IsLeftShiftDown())
{
return SListView<ItemType>::OnMouseWheel(MyGeometry, MouseEvent);
};
return FReply::Unhandled();
}
void RefreshList()
{
const TArray<ItemType>& ItemsSourceRef = (*this->ItemsSource);
for (int32 Index = 0; Index < ItemsSourceRef.Num(); ++Index)
{
TSharedPtr< SLogsTableRow > TableRow = StaticCastSharedPtr< SLogsTableRow >(this->WidgetGenerator.GetWidgetForItem(ItemsSourceRef[Index]));
if (TableRow.IsValid())
{
TableRow->UpdateEntries();
}
}
}
};
BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION
void SLogVisualizer::Construct(const FArguments& InArgs, FLogVisualizer* InLogVisualizer)
{
LogVisualizer = InLogVisualizer;
SortBy = ELogsSortMode::ByName;
LogEntryIndex = INDEX_NONE;
SelectedLogIndex = INDEX_NONE;
LogsStartTime = FLT_MAX;
LogsEndTime = -FLT_MAX;
ScrollbarOffset = 0.f;
ZoomSliderValue = 0.f;
LastBarsOffset = 0.f;
MinZoom = 1.0f;
MaxZoom = 20.0f;
CurrentViewedTime = 0.f;
bDrawLogEntriesPath = true;
bIgnoreTrivialLogs = true;
HistogramPreviewWindow = 50;
bShowHistogramLabelsOutside = false;
bStickToLastData = false;
bOffsetDataSet = false;
bHistogramGraphsFilter = true;
UsedCategories.Empty();
ChildSlot
[
SNew(SBorder)
.BorderImage(FEditorStyle::GetBrush("ToolPanel.GroupBorder"))
[
SNew(SVerticalBox)
// Toolbar
+SVerticalBox::Slot()
.AutoHeight()
[
SNew( SOverlay )
+ SOverlay::Slot()
[
SNew(SHorizontalBox)
// Record button
+SHorizontalBox::Slot()
.AutoWidth()
.Padding(1)
[
SNew(SButton)
.OnClicked(this, &SLogVisualizer::OnRecordButtonClicked)
.Content()
[
SNew(SImage)
.Image(this, &SLogVisualizer::GetRecordButtonBrush)
]
]
// 'Pause' toggle button
+SHorizontalBox::Slot()
.AutoWidth()
.Padding(1)
[
SNew(SCheckBox)
.Style(FEditorStyle::Get(), "ToggleButtonCheckbox")
.OnCheckStateChanged(this, &SLogVisualizer::OnPauseChanged)
.IsChecked(this, &SLogVisualizer::GetPauseState)
.Content()
[
SNew(SImage)
.Image(FEditorStyle::GetBrush("LogVisualizer.Pause"))
]
]
// 'Camera' toggle button
+SHorizontalBox::Slot()
.AutoWidth()
.Padding(1)
[
SNew(SCheckBox)
.Style(FEditorStyle::Get(), "ToggleButtonCheckbox")
.OnCheckStateChanged(this, &SLogVisualizer::OnToggleCamera)
.IsChecked(this, &SLogVisualizer::GetToggleCameraState)
.Content()
[
SNew(SImage)
.Image(FEditorStyle::GetBrush("LogVisualizer.Camera"))
]
]
+SHorizontalBox::Slot()
.MaxWidth(3)
.Padding(1)
[
SNew(SSeparator)
.Orientation(Orient_Vertical)
]
// 'Save' function
+SHorizontalBox::Slot()
.AutoWidth()
.Padding(1)
[
SNew(SButton)
.OnClicked(this, &SLogVisualizer::OnSave)
.Content()
[
SNew(SImage)
.Image(FEditorStyle::GetBrush("LogVisualizer.Save"))
]
]
// 'Load' function
+SHorizontalBox::Slot()
.AutoWidth()
.Padding(1)
[
SNew(SButton)
.OnClicked(this, &SLogVisualizer::OnLoad)
.Content()
[
SNew(SImage)
.Image(FEditorStyle::GetBrush("LogVisualizer.Load"))
]
]
// 'Remove' function
+SHorizontalBox::Slot()
.AutoWidth()
.Padding(1)
[
SNew(SButton)
.OnClicked(this, &SLogVisualizer::OnRemove)
.Content()
[
SNew(SImage)
.Image(FEditorStyle::GetBrush("LogVisualizer.Remove"))
]
]
+SHorizontalBox::Slot()
.MaxWidth(3)
.Padding(1)
[
SNew(SSeparator)
.Orientation(Orient_Vertical)
]
]
+ SOverlay::Slot()
.HAlign(HAlign_Right)
.Padding(4)
[
SNew(SComboButton)
.ComboButtonStyle(FEditorStyle::Get(), "ContentBrowser.Filters.Style")
.ForegroundColor(FLinearColor::White)
.ContentPadding(0)
.ToolTipText(LOCTEXT("SettingsToolTip", "Log Visualizer settings."))
.HasDownArrow(true)
.ContentPadding(FMargin(1, 0))
.ButtonContent()
[
SNew(STextBlock)
.TextStyle(FEditorStyle::Get(), "ContentBrowser.Filters.Text")
.Text(LOCTEXT("Settings", "Settings"))
]
.MenuContent()
[
SNew(SVerticalBox)
+ SVerticalBox::Slot()
.AutoHeight()
[
SNew(SCheckBox)
.OnCheckStateChanged(this, &SLogVisualizer::OnDrawLogEntriesPathChanged)
.IsChecked(this, &SLogVisualizer::GetDrawLogEntriesPathState)
.Content()
[
SNew(STextBlock)
.Text(LOCTEXT("VisLogDrawLogsPath", "Draw Log\'s path"))
.ToolTipText(LOCTEXT("VisLogDrawLogsPathTooltip", "Toggle whether path of composed of log entries\' locations"))
]
]
+ SVerticalBox::Slot()
.AutoHeight()
[
SNew(SCheckBox)
.OnCheckStateChanged(this, &SLogVisualizer::OnIgnoreTrivialLogs)
.IsChecked(this, &SLogVisualizer::GetIgnoreTrivialLogs)
.Content()
[
SNew(STextBlock)
.Text(LOCTEXT("VisLogIgnoreTrivialLogs", "Ignore trivial logs"))
.ToolTipText(LOCTEXT("VisLogIgnoreTrivialLogsTooltip", "Whether to show trivial logs, i.e. the ones with only one entry."))
]
]
+ SVerticalBox::Slot()
.AutoHeight()
[
SNew(SCheckBox)
.OnCheckStateChanged(this, &SLogVisualizer::OnChangeHistogramLabelLocation)
.IsChecked(this, &SLogVisualizer::GetHistogramLabelLocation)
.Content()
[
SNew(STextBlock)
.Text(LOCTEXT("VisLogHistogramLabelLocation", "Set histogram labels outside graph"))
.ToolTipText(LOCTEXT("VisLogHistogramLabelLocationTooltip", "Whether to show histogram labels inside graph or outside."))
]
]
+ SVerticalBox::Slot()
.AutoHeight()
[
SNew(SCheckBox)
.OnCheckStateChanged(this, &SLogVisualizer::OnStickToLastData)
.IsChecked(this, &SLogVisualizer::GetStickToLastData)
.Content()
[
SNew(STextBlock)
.Text(LOCTEXT("VisLogStickToLastData", "Stick to recent data"))
.ToolTipText(LOCTEXT("VisLogStickToLastDataTooltip", "Whether to show the recent data or not."))
]
]
+ SVerticalBox::Slot()
.AutoHeight()
[
SNew(SCheckBox)
.OnCheckStateChanged(this, &SLogVisualizer::OnOffsetDataSets)
.IsChecked(this, &SLogVisualizer::GetOffsetDataSets)
.Content()
[
SNew(STextBlock)
.Text(LOCTEXT("VisLogOffsetDataSets", "Offset data sets"))
.ToolTipText(LOCTEXT("VisLogOffsetDataSetsTooltip", "Offset data sets on graphs to make it easier to read"))
]
]
]
]
]
// Filters
+ SVerticalBox::Slot()
.AutoHeight()
[
SAssignNew(FilterListPtr, SLogFilterList)
.OnFilterChanged(this, &SLogVisualizer::OnLogCategoryFiltersChanged)
.AddMetaData<FTagMetaData>(FTagMetaData(TEXT("CategoryFilters")))
/*.OnGetContextMenu(this, &SLogVisualizer::GetFilterContextMenu)*/
/*.FrontendFilters(FrontendFilters)*/
]
+SVerticalBox::Slot()
.FillHeight(5)
[
SNew(SSplitter)
.Orientation(Orient_Vertical)
+SSplitter::Slot()
[
SNew(SBorder)
.BorderImage(FEditorStyle::GetBrush("Menu.Background"))
.Padding(1.0)
[
SAssignNew(LogsListWidget, SLogListView< TSharedPtr<FLogsListItem> >)
.ItemHeight(20)
Merging using UE4-Fortnite-To-UE4 up to CL 2082758 Includes following engine CLs: CL 2080462: Added verbosity selection to category filters in Log Visualizer window CL 2081939: Fixed crash in Log Visualizer and missing entry on timeline with log containing only 2 entries. CL 2082118: Fixes and improovements for VisLogs - fixed logs visualization for logs with only one entry (Log Visualizer window) - fixed logs spam about missing json field (Log Visualizer window) - fixed crash with categories in Log Visualization window - added category and verbosity serialization for vislog shape elements (vlog files) CL 2080253: Added categories to VisLog shapes CL 2081762: Fixes to Log Visualizer. Logs without any log lines but with geometry elements are set on timeline properly. CL 2081859: Added double click to Log Visualizer action, to move editor camera to view current log location CL 2080159: Gameply Tag Pin now only allows single select #TTP 335383 - Editor: GameplayTag Pin should only allow a single selection #proj UE4 #change Removes all other tags from the correct container when in single select mode, was a missed variable change from a previous TTP CL 2081306: Made changes to navigation filters that allow for usage of virtual verstion dtQueryFilter #UE4 The scary part here is that having a dtQueryFilter contan a vftable was messing up FRecastQueryFilter's vftable it was getting from INavigationQueryFilterInterface. Reversing order of parent clas declaration of FRecastQueryFilter fixed the issue, but it's scary and looks like a compiler issue. [CL 2088758 by Billy Bramer in Main branch]
2014-05-29 17:46:51 -04:00
// Called when the user double-clicks with LMB on an item in the list
.OnMouseButtonDoubleClick(this, &SLogVisualizer::OnListDoubleClick)
.ListItemsSource(&LogsList)
.SelectionMode(ESelectionMode::Multi)
.OnGenerateRow(this, &SLogVisualizer::LogsListGenerateRow)
.OnSelectionChanged(this, &SLogVisualizer::LogsListSelectionChanged)
.HeaderRow(
SNew(SHeaderRow)
// ID
+SHeaderRow::Column(NAME_LogName)
.SortMode(this, &SLogVisualizer::GetLogsSortMode)
.OnSort(this, &SLogVisualizer::OnSortByChanged)
.HAlignCell(HAlign_Left)
.FillWidth(0.25f)
[
SNew(SHorizontalBox)
+SHorizontalBox::Slot()
.AutoWidth()
.HAlign(HAlign_Left)
.Padding(0.0, 2.0)
[
SNew(STextBlock)
.Text(LOCTEXT("VisLogName", "Log Subject"))
]
+SHorizontalBox::Slot()
.AutoWidth()
.Padding(5,0)
[
SAssignNew(LogNameFilterBox, SEditableTextBox)
.SelectAllTextWhenFocused(true)
.OnTextCommitted(this, &SLogVisualizer::FilterTextCommitted)
.MinDesiredWidth(90.f)
.RevertTextOnEscape(true)
]
]
+SHeaderRow::Column(NAME_LogTimeSpan)
.VAlignCell(VAlign_Center)
[
SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
.AutoWidth()
.HAlign(HAlign_Center)
.Padding(0.0, 2.0)
[
SNew(STextBlock)
.Text(LOCTEXT("VisLogFilterName", "Quick Filter"))
]
+ SHorizontalBox::Slot()
.AutoWidth()
.Padding(5, 0)
[
SAssignNew(QuickFilterBox, SEditableTextBox)
.SelectAllTextWhenFocused(true)
.OnTextChanged(this, &SLogVisualizer::OnQuickFilterTextChanged, ETextCommit::Default)
.MinDesiredWidth(170.f)
.RevertTextOnEscape(true)
]
+ SHorizontalBox::Slot()
.AutoWidth()
[
SNew(SCheckBox)
.OnCheckStateChanged(this, &SLogVisualizer::OnHistogramGraphsFilter)
.IsChecked(this, &SLogVisualizer::GetHistogramGraphsFilter)
.Content()
[
SNew(STextBlock)
.Text(LOCTEXT("VisLogHistogramGraphsFilter", "histogram graphs filter"))
.ToolTipText(LOCTEXT("VisLogHistogramGraphsFilterTooltip", "Whether to filter histogram graphs or regular categories."))
]
]
]
)
]
]
+SSplitter::Slot()
[
SNew(SBorder)
.BorderImage(FEditorStyle::GetBrush("Menu.Background"))
.Padding(1.0)
[
SNew(SVerticalBox)
+SVerticalBox::Slot()
.AutoHeight()
.MaxHeight(60)
[
SAssignNew( Timeline, STimeline )
.MinValue(0.0f)
.MaxValue(100.0f)
.FixedLabelSpacing(100.f)
]
+SVerticalBox::Slot()
.AutoHeight()
.Padding( 2 )
.VAlign( VAlign_Fill )
[
SAssignNew( ScrollBar, SScrollBar )
.Orientation( Orient_Horizontal )
.OnUserScrolled( this, &SLogVisualizer::OnZoomScrolled )
]
+SVerticalBox::Slot()
.AutoHeight()
.Padding( 2 )
[
SAssignNew(ZoomSlider, SSlider)
.Value( this, &SLogVisualizer::GetZoomValue )
.OnValueChanged( this, &SLogVisualizer::OnSetZoomValue )
]
+SVerticalBox::Slot()
.Padding(2)
.FillHeight(3)
//.VAlign(VAlign_Fill)
[
SNew(SSplitter)
+SSplitter::Slot()
.Value(1)
[
SNew( SBorder )
.Padding(1)
.BorderImage( FEditorStyle::GetBrush( "ToolBar.Background" ) )
[
SAssignNew(StatusItemsView, STreeView<TSharedPtr<FLogStatusItem> >)
.ItemHeight(40.0f)
.TreeItemsSource(&StatusItems)
.OnGenerateRow(this, &SLogVisualizer::HandleGenerateLogStatus)
.OnGetChildren(this, &SLogVisualizer::OnLogStatusGetChildren)
.SelectionMode(ESelectionMode::None)
]
]
+SSplitter::Slot()
.Value(3)
[
SNew( SBorder )
.Padding(1)
.BorderImage( FEditorStyle::GetBrush( "ToolBar.Background" ) )
[
SAssignNew(LogsLinesWidget, SListView<TSharedPtr<FLogEntryItem> >)
.ItemHeight(20)
.ListItemsSource(&LogEntryLines)
.SelectionMode(ESelectionMode::Single)
.OnSelectionChanged(this, &SLogVisualizer::LogEntryLineSelectionChanged)
.OnGenerateRow(this, &SLogVisualizer::LogEntryLinesGenerateRow)
]
]
]
]
]
]
+SVerticalBox::Slot()
.AutoHeight()
[
// Status area
SNew(STextBlock)
.Text(this, &SLogVisualizer::GetStatusText)
]
]
];
LogVisualizer->OnLogAdded().AddSP(this, &SLogVisualizer::OnLogAdded);
if (LogsList.Num() == 0)
{
Timeline->SetVisibility(EVisibility::Hidden);
ScrollBar->SetVisibility(EVisibility::Hidden);
ZoomSlider->SetVisibility(EVisibility::Hidden);
}
TArray<TSharedPtr<FActorsVisLog> >& Logs = LogVisualizer->Logs;
TSharedPtr<FActorsVisLog>* SharedLog = Logs.GetTypedData();
for (int32 LogIndex = 0; LogIndex < Logs.Num(); ++LogIndex, ++SharedLog)
{
if (SharedLog->IsValid())
{
AddOrUpdateLog(LogIndex, SharedLog->Get());
}
}
DoFullUpdate();
LastBrowsePath = FPaths::GameLogDir();
DrawingOnCanvasDelegate = FDebugDrawDelegate::CreateSP(this, &SLogVisualizer::DrawOnCanvas);
UDebugDrawService::Register(TEXT("VisLog"), DrawingOnCanvasDelegate);
UGameplayDebuggingComponent::OnDebuggingTargetChangedDelegate.AddSP(this, &SLogVisualizer::SelectionChanged);
}
END_SLATE_FUNCTION_BUILD_OPTIMIZATION
SLogVisualizer::~SLogVisualizer()
{
UWorld* World = GetWorld();
if (World)
{
World->DestroyActor(FLogVisualizerModule::Get()->GetHelperActor(World));
}
UGameplayDebuggingComponent::OnDebuggingTargetChangedDelegate.RemoveAll(this);
LogVisualizer->OnLogAdded().RemoveAll(this);
UDebugDrawService::Unregister(DrawingOnCanvasDelegate);
InvalidateCanvas();
}
Merging using UE4-Fortnite-To-UE4 up to CL 2082758 Includes following engine CLs: CL 2080462: Added verbosity selection to category filters in Log Visualizer window CL 2081939: Fixed crash in Log Visualizer and missing entry on timeline with log containing only 2 entries. CL 2082118: Fixes and improovements for VisLogs - fixed logs visualization for logs with only one entry (Log Visualizer window) - fixed logs spam about missing json field (Log Visualizer window) - fixed crash with categories in Log Visualization window - added category and verbosity serialization for vislog shape elements (vlog files) CL 2080253: Added categories to VisLog shapes CL 2081762: Fixes to Log Visualizer. Logs without any log lines but with geometry elements are set on timeline properly. CL 2081859: Added double click to Log Visualizer action, to move editor camera to view current log location CL 2080159: Gameply Tag Pin now only allows single select #TTP 335383 - Editor: GameplayTag Pin should only allow a single selection #proj UE4 #change Removes all other tags from the correct container when in single select mode, was a missed variable change from a previous TTP CL 2081306: Made changes to navigation filters that allow for usage of virtual verstion dtQueryFilter #UE4 The scary part here is that having a dtQueryFilter contan a vftable was messing up FRecastQueryFilter's vftable it was getting from INavigationQueryFilterInterface. Reversing order of parent clas declaration of FRecastQueryFilter fixed the issue, but it's scary and looks like a compiler issue. [CL 2088758 by Billy Bramer in Main branch]
2014-05-29 17:46:51 -04:00
void SLogVisualizer::OnListDoubleClick(TSharedPtr<FLogsListItem> LogListItem)
{
#if WITH_EDITOR
FVector Orgin, Extent;
bool bFoundActor = false;
if (LogVisualizer->Logs.IsValidIndex(LogListItem->LogIndex))
{
TSharedPtr<FActorsVisLog>& Log = LogVisualizer->Logs[LogListItem->LogIndex];
for (FActorIterator It(GetWorld()); It; ++It)
{
AActor* Actor = *It;
Merging using UE4-Fortnite-To-UE4 up to CL 2082758 Includes following engine CLs: CL 2080462: Added verbosity selection to category filters in Log Visualizer window CL 2081939: Fixed crash in Log Visualizer and missing entry on timeline with log containing only 2 entries. CL 2082118: Fixes and improovements for VisLogs - fixed logs visualization for logs with only one entry (Log Visualizer window) - fixed logs spam about missing json field (Log Visualizer window) - fixed crash with categories in Log Visualization window - added category and verbosity serialization for vislog shape elements (vlog files) CL 2080253: Added categories to VisLog shapes CL 2081762: Fixes to Log Visualizer. Logs without any log lines but with geometry elements are set on timeline properly. CL 2081859: Added double click to Log Visualizer action, to move editor camera to view current log location CL 2080159: Gameply Tag Pin now only allows single select #TTP 335383 - Editor: GameplayTag Pin should only allow a single selection #proj UE4 #change Removes all other tags from the correct container when in single select mode, was a missed variable change from a previous TTP CL 2081306: Made changes to navigation filters that allow for usage of virtual verstion dtQueryFilter #UE4 The scary part here is that having a dtQueryFilter contan a vftable was messing up FRecastQueryFilter's vftable it was getting from INavigationQueryFilterInterface. Reversing order of parent clas declaration of FRecastQueryFilter fixed the issue, but it's scary and looks like a compiler issue. [CL 2088758 by Billy Bramer in Main branch]
2014-05-29 17:46:51 -04:00
if (Actor->GetFName() == Log->Name)
{
Actor->GetActorBounds(false, Orgin, Extent);
bFoundActor = true;
break;
}
}
}
if (!bFoundActor)
{
Extent = FVector(150, 150, 150);
Merging using UE4-Fortnite-To-UE4 up to CL 2082758 Includes following engine CLs: CL 2080462: Added verbosity selection to category filters in Log Visualizer window CL 2081939: Fixed crash in Log Visualizer and missing entry on timeline with log containing only 2 entries. CL 2082118: Fixes and improovements for VisLogs - fixed logs visualization for logs with only one entry (Log Visualizer window) - fixed logs spam about missing json field (Log Visualizer window) - fixed crash with categories in Log Visualization window - added category and verbosity serialization for vislog shape elements (vlog files) CL 2080253: Added categories to VisLog shapes CL 2081762: Fixes to Log Visualizer. Logs without any log lines but with geometry elements are set on timeline properly. CL 2081859: Added double click to Log Visualizer action, to move editor camera to view current log location CL 2080159: Gameply Tag Pin now only allows single select #TTP 335383 - Editor: GameplayTag Pin should only allow a single selection #proj UE4 #change Removes all other tags from the correct container when in single select mode, was a missed variable change from a previous TTP CL 2081306: Made changes to navigation filters that allow for usage of virtual verstion dtQueryFilter #UE4 The scary part here is that having a dtQueryFilter contan a vftable was messing up FRecastQueryFilter's vftable it was getting from INavigationQueryFilterInterface. Reversing order of parent clas declaration of FRecastQueryFilter fixed the issue, but it's scary and looks like a compiler issue. [CL 2088758 by Billy Bramer in Main branch]
2014-05-29 17:46:51 -04:00
}
if (LogVisualizer->Logs.IsValidIndex(LogListItem->LogIndex))
{
TSharedPtr<FActorsVisLog>& Log = LogVisualizer->Logs[LogListItem->LogIndex];
if (Log.IsValid() && Log->Entries.IsValidIndex(LogEntryIndex))
{
Orgin = Log->Entries[LogEntryIndex]->Location;
}
}
UEditorEngine *EEngine = Cast<UEditorEngine>(GEngine);
if (GIsEditor && EEngine != NULL)
{
for (auto ViewportClient : EEngine->AllViewportClients)
Merging using UE4-Fortnite-To-UE4 up to CL 2082758 Includes following engine CLs: CL 2080462: Added verbosity selection to category filters in Log Visualizer window CL 2081939: Fixed crash in Log Visualizer and missing entry on timeline with log containing only 2 entries. CL 2082118: Fixes and improovements for VisLogs - fixed logs visualization for logs with only one entry (Log Visualizer window) - fixed logs spam about missing json field (Log Visualizer window) - fixed crash with categories in Log Visualization window - added category and verbosity serialization for vislog shape elements (vlog files) CL 2080253: Added categories to VisLog shapes CL 2081762: Fixes to Log Visualizer. Logs without any log lines but with geometry elements are set on timeline properly. CL 2081859: Added double click to Log Visualizer action, to move editor camera to view current log location CL 2080159: Gameply Tag Pin now only allows single select #TTP 335383 - Editor: GameplayTag Pin should only allow a single selection #proj UE4 #change Removes all other tags from the correct container when in single select mode, was a missed variable change from a previous TTP CL 2081306: Made changes to navigation filters that allow for usage of virtual verstion dtQueryFilter #UE4 The scary part here is that having a dtQueryFilter contan a vftable was messing up FRecastQueryFilter's vftable it was getting from INavigationQueryFilterInterface. Reversing order of parent clas declaration of FRecastQueryFilter fixed the issue, but it's scary and looks like a compiler issue. [CL 2088758 by Billy Bramer in Main branch]
2014-05-29 17:46:51 -04:00
{
ViewportClient->FocusViewportOnBox(FBox::BuildAABB(Orgin, Extent));
}
}
else if (ALogVisualizerCameraController::IsEnabled(GetWorld()) && CameraController.IsValid() && CameraController->GetSpectatorPawn())
{
ULocalPlayer* LocalPlayer = Cast<ULocalPlayer>(CameraController->Player);
if (LocalPlayer && LocalPlayer->ViewportClient && LocalPlayer->ViewportClient->Viewport)
{
FViewport* Viewport = LocalPlayer->ViewportClient->Viewport;
FBox BoundingBox = FBox::BuildAABB(Orgin, Extent);
const FVector Position = BoundingBox.GetCenter();
float Radius = BoundingBox.GetExtent().Size();
FViewportCameraTransform ViewTransform;
ViewTransform.TransitionToLocation(Position, true);
float NewOrthoZoom;
const float AspectRatio = 1.777777f;
uint32 MinAxisSize = (AspectRatio > 1.0f) ? Viewport->GetSizeXY().Y : Viewport->GetSizeXY().X;
float Zoom = Radius / (MinAxisSize / 2);
NewOrthoZoom = Zoom * (Viewport->GetSizeXY().X*15.0f);
NewOrthoZoom = FMath::Clamp<float>(NewOrthoZoom, 250, MAX_FLT);
ViewTransform.SetOrthoZoom(NewOrthoZoom);
CameraController->GetSpectatorPawn()->TeleportTo(ViewTransform.GetLocation(), ViewTransform.GetRotation(), false, true);
}
}
Merging using UE4-Fortnite-To-UE4 up to CL 2082758 Includes following engine CLs: CL 2080462: Added verbosity selection to category filters in Log Visualizer window CL 2081939: Fixed crash in Log Visualizer and missing entry on timeline with log containing only 2 entries. CL 2082118: Fixes and improovements for VisLogs - fixed logs visualization for logs with only one entry (Log Visualizer window) - fixed logs spam about missing json field (Log Visualizer window) - fixed crash with categories in Log Visualization window - added category and verbosity serialization for vislog shape elements (vlog files) CL 2080253: Added categories to VisLog shapes CL 2081762: Fixes to Log Visualizer. Logs without any log lines but with geometry elements are set on timeline properly. CL 2081859: Added double click to Log Visualizer action, to move editor camera to view current log location CL 2080159: Gameply Tag Pin now only allows single select #TTP 335383 - Editor: GameplayTag Pin should only allow a single selection #proj UE4 #change Removes all other tags from the correct container when in single select mode, was a missed variable change from a previous TTP CL 2081306: Made changes to navigation filters that allow for usage of virtual verstion dtQueryFilter #UE4 The scary part here is that having a dtQueryFilter contan a vftable was messing up FRecastQueryFilter's vftable it was getting from INavigationQueryFilterInterface. Reversing order of parent clas declaration of FRecastQueryFilter fixed the issue, but it's scary and looks like a compiler issue. [CL 2088758 by Billy Bramer in Main branch]
2014-05-29 17:46:51 -04:00
#endif
}
int32 SLogVisualizer::GetCurrentVisibleLogEntryIndex(const TArray<TSharedPtr<FVisLogEntry> >& InVisibleEntries)
{
if (LogVisualizer->Logs.IsValidIndex(SelectedLogIndex))
{
TSharedPtr<FActorsVisLog> Log = LogVisualizer->Logs[SelectedLogIndex];
if (Log.IsValid() && Log->Entries.IsValidIndex(LogEntryIndex))
{
for (int32 Index = 0; Index < InVisibleEntries.Num(); ++Index)
{
if (InVisibleEntries[Index] == Log->Entries[LogEntryIndex])
{
return Index;
}
}
}
}
return INDEX_NONE;
}
void SLogVisualizer::UpdateVisibleEntriesCache(const TSharedPtr<FActorsVisLog>& Log, int32 Index)
{
int32 CurrentIndex = INDEX_NONE;
int32 LogListNum = LogsList.Num();
for (int32 LogIndex = 0; LogIndex < LogListNum; ++LogIndex)
{
if (LogsList[LogIndex]->LogIndex == Index)
{
CurrentIndex = LogIndex;
break;
}
}
float LastTimestamp = -1;
if (CurrentIndex != INDEX_NONE)
{
LastTimestamp = LogsList[CurrentIndex]->LastEndTimestamp;
}
const int32 NumLogs = OutEntriesCached.Num();
int32 CachedLogIndex = INDEX_NONE;
for (int32 EntriesIndex = 0; EntriesIndex < NumLogs; ++EntriesIndex)
{
if (OutEntriesCached[EntriesIndex].Log == Log)
{
CachedLogIndex = EntriesIndex;
break;
}
}
if (CachedLogIndex == INDEX_NONE)
{
FCachedEntries CachedLog;
CachedLog.Log = Log;
CachedLogIndex = OutEntriesCached.Add(CachedLog);
}
if (FilterListPtr.IsValid())
{
for (int32 EntryIndex = 0; EntryIndex < Log->Entries.Num(); ++EntryIndex)
{
const TSharedPtr<FVisLogEntry> CurrentEntry = Log->Entries[EntryIndex];
if (CurrentEntry->TimeStamp <= LastTimestamp)
{
continue;
}
bool bAddedEntry = false;
if (!bAddedEntry)
{
for (int32 LogLineIndex = 0; LogLineIndex < CurrentEntry->LogLines.Num(); ++LogLineIndex)
{
const FVisLogEntry::FLogLine &CurrentLine = CurrentEntry->LogLines[LogLineIndex];
const FString CurrentCategory = CurrentLine.Category.ToString();
if (FilterListPtr->IsFilterEnabled(CurrentCategory, CurrentLine.Verbosity))
{
OutEntriesCached[CachedLogIndex].CachedEntries.Add(CurrentEntry);
bAddedEntry = true;
break;
}
}
}
Merging using UE4-Fortnite-To-UE4 up to CL 2082758 Includes following engine CLs: CL 2080462: Added verbosity selection to category filters in Log Visualizer window CL 2081939: Fixed crash in Log Visualizer and missing entry on timeline with log containing only 2 entries. CL 2082118: Fixes and improovements for VisLogs - fixed logs visualization for logs with only one entry (Log Visualizer window) - fixed logs spam about missing json field (Log Visualizer window) - fixed crash with categories in Log Visualization window - added category and verbosity serialization for vislog shape elements (vlog files) CL 2080253: Added categories to VisLog shapes CL 2081762: Fixes to Log Visualizer. Logs without any log lines but with geometry elements are set on timeline properly. CL 2081859: Added double click to Log Visualizer action, to move editor camera to view current log location CL 2080159: Gameply Tag Pin now only allows single select #TTP 335383 - Editor: GameplayTag Pin should only allow a single selection #proj UE4 #change Removes all other tags from the correct container when in single select mode, was a missed variable change from a previous TTP CL 2081306: Made changes to navigation filters that allow for usage of virtual verstion dtQueryFilter #UE4 The scary part here is that having a dtQueryFilter contan a vftable was messing up FRecastQueryFilter's vftable it was getting from INavigationQueryFilterInterface. Reversing order of parent clas declaration of FRecastQueryFilter fixed the issue, but it's scary and looks like a compiler issue. [CL 2088758 by Billy Bramer in Main branch]
2014-05-29 17:46:51 -04:00
if (bAddedEntry)
{
continue;
}
for (int32 ElementIndex = 0; ElementIndex < CurrentEntry->ElementsToDraw.Num(); ++ElementIndex)
Merging using UE4-Fortnite-To-UE4 up to CL 2082758 Includes following engine CLs: CL 2080462: Added verbosity selection to category filters in Log Visualizer window CL 2081939: Fixed crash in Log Visualizer and missing entry on timeline with log containing only 2 entries. CL 2082118: Fixes and improovements for VisLogs - fixed logs visualization for logs with only one entry (Log Visualizer window) - fixed logs spam about missing json field (Log Visualizer window) - fixed crash with categories in Log Visualization window - added category and verbosity serialization for vislog shape elements (vlog files) CL 2080253: Added categories to VisLog shapes CL 2081762: Fixes to Log Visualizer. Logs without any log lines but with geometry elements are set on timeline properly. CL 2081859: Added double click to Log Visualizer action, to move editor camera to view current log location CL 2080159: Gameply Tag Pin now only allows single select #TTP 335383 - Editor: GameplayTag Pin should only allow a single selection #proj UE4 #change Removes all other tags from the correct container when in single select mode, was a missed variable change from a previous TTP CL 2081306: Made changes to navigation filters that allow for usage of virtual verstion dtQueryFilter #UE4 The scary part here is that having a dtQueryFilter contan a vftable was messing up FRecastQueryFilter's vftable it was getting from INavigationQueryFilterInterface. Reversing order of parent clas declaration of FRecastQueryFilter fixed the issue, but it's scary and looks like a compiler issue. [CL 2088758 by Billy Bramer in Main branch]
2014-05-29 17:46:51 -04:00
{
const FString CurrentCategory = CurrentEntry->ElementsToDraw[ElementIndex].Category.ToString();
FVisLogEntry::FElementToDraw &CurrentElement = CurrentEntry->ElementsToDraw[ElementIndex];
if (CurrentElement.Category != NAME_None && (FilterListPtr->IsFilterEnabled(CurrentCategory, CurrentElement.Verbosity)))
Merging using UE4-Fortnite-To-UE4 up to CL 2082758 Includes following engine CLs: CL 2080462: Added verbosity selection to category filters in Log Visualizer window CL 2081939: Fixed crash in Log Visualizer and missing entry on timeline with log containing only 2 entries. CL 2082118: Fixes and improovements for VisLogs - fixed logs visualization for logs with only one entry (Log Visualizer window) - fixed logs spam about missing json field (Log Visualizer window) - fixed crash with categories in Log Visualization window - added category and verbosity serialization for vislog shape elements (vlog files) CL 2080253: Added categories to VisLog shapes CL 2081762: Fixes to Log Visualizer. Logs without any log lines but with geometry elements are set on timeline properly. CL 2081859: Added double click to Log Visualizer action, to move editor camera to view current log location CL 2080159: Gameply Tag Pin now only allows single select #TTP 335383 - Editor: GameplayTag Pin should only allow a single selection #proj UE4 #change Removes all other tags from the correct container when in single select mode, was a missed variable change from a previous TTP CL 2081306: Made changes to navigation filters that allow for usage of virtual verstion dtQueryFilter #UE4 The scary part here is that having a dtQueryFilter contan a vftable was messing up FRecastQueryFilter's vftable it was getting from INavigationQueryFilterInterface. Reversing order of parent clas declaration of FRecastQueryFilter fixed the issue, but it's scary and looks like a compiler issue. [CL 2088758 by Billy Bramer in Main branch]
2014-05-29 17:46:51 -04:00
{
OutEntriesCached[CachedLogIndex].CachedEntries.AddUnique(CurrentEntry);
bAddedEntry = true;
Merging using UE4-Fortnite-To-UE4 up to CL 2082758 Includes following engine CLs: CL 2080462: Added verbosity selection to category filters in Log Visualizer window CL 2081939: Fixed crash in Log Visualizer and missing entry on timeline with log containing only 2 entries. CL 2082118: Fixes and improovements for VisLogs - fixed logs visualization for logs with only one entry (Log Visualizer window) - fixed logs spam about missing json field (Log Visualizer window) - fixed crash with categories in Log Visualization window - added category and verbosity serialization for vislog shape elements (vlog files) CL 2080253: Added categories to VisLog shapes CL 2081762: Fixes to Log Visualizer. Logs without any log lines but with geometry elements are set on timeline properly. CL 2081859: Added double click to Log Visualizer action, to move editor camera to view current log location CL 2080159: Gameply Tag Pin now only allows single select #TTP 335383 - Editor: GameplayTag Pin should only allow a single selection #proj UE4 #change Removes all other tags from the correct container when in single select mode, was a missed variable change from a previous TTP CL 2081306: Made changes to navigation filters that allow for usage of virtual verstion dtQueryFilter #UE4 The scary part here is that having a dtQueryFilter contan a vftable was messing up FRecastQueryFilter's vftable it was getting from INavigationQueryFilterInterface. Reversing order of parent clas declaration of FRecastQueryFilter fixed the issue, but it's scary and looks like a compiler issue. [CL 2088758 by Billy Bramer in Main branch]
2014-05-29 17:46:51 -04:00
break;
}
}
if (bAddedEntry)
{
continue;
}
for (int32 SampleIndex = 0; SampleIndex < CurrentEntry->HistogramSamples.Num(); ++SampleIndex)
{
const FVisLogEntry::FHistogramSample &CurrentSample = CurrentEntry->HistogramSamples[SampleIndex];
const FName CurrentCategory = CurrentSample.Category;
const FName CurrentDataName = CurrentSample.DataName;
const bool bCurrentCategoryPassed = FilterListPtr->IsFilterEnabled(CurrentCategory.ToString(), ELogVerbosity::All);
const bool bCurrentDataNamePassed = FilterListPtr->IsFilterEnabled(CurrentDataName.ToString(), ELogVerbosity::All);
if (CurrentCategory != NAME_None && (bCurrentCategoryPassed && bCurrentDataNamePassed))
{
OutEntriesCached[CachedLogIndex].CachedEntries.AddUnique(CurrentEntry);
bAddedEntry = true;
break;
}
}
if (bAddedEntry)
{
continue;
}
for (const auto CurrentBlock : CurrentEntry->DataBlocks)
{
const bool bCurrentCategoryPassed = FilterListPtr->IsFilterEnabled(CurrentBlock.Category.ToString(), ELogVerbosity::All);
const bool bCurrentTagNamePassed = FilterListPtr->IsFilterEnabled(CurrentBlock.TagName.ToString(), ELogVerbosity::All);
if (CurrentBlock.Category != NAME_None && (bCurrentCategoryPassed && bCurrentTagNamePassed))
{
OutEntriesCached[CachedLogIndex].CachedEntries.AddUnique(CurrentEntry);
bAddedEntry = true;
break;
}
}
}
}
else
{
// if there is no LogFilter widget - show all
OutEntriesCached[CachedLogIndex].CachedEntries = Log->Entries;
}
LogsList[CurrentIndex]->LastEndTimestamp = LogsList[CurrentIndex]->EndTimestamp;
}
void SLogVisualizer::GetVisibleEntries(const TSharedPtr<FActorsVisLog>& Log, TArray<TSharedPtr<FVisLogEntry> >& OutEntries)
{
const int32 NumLogs = OutEntriesCached.Num();
int32 CachedLogIndex = INDEX_NONE;
for (int32 Index = 0; Index < NumLogs; ++Index)
{
if (OutEntriesCached[Index].Log == Log)
{
CachedLogIndex = Index;
break;
}
}
if (CachedLogIndex == INDEX_NONE)
{
FCachedEntries CachedLog;
CachedLog.Log = Log;
CachedLogIndex = OutEntriesCached.Add(CachedLog);
}
if (OutEntriesCached[CachedLogIndex].CachedEntries.Num() == 0)
{
// generate entries based on current filters
OutEntriesCached[CachedLogIndex].CachedEntries.Reset();
if (FilterListPtr.IsValid())
{
for (int32 i = 0; i < Log->Entries.Num(); ++i)
{
bool bAddedEntry = false;
const TSharedPtr<FVisLogEntry> CurrentEntry = Log->Entries[i];
if (!bAddedEntry)
{
for (int32 j = 0; j < CurrentEntry->LogLines.Num(); ++j)
{
const FVisLogEntry::FLogLine &CurrentLine = CurrentEntry->LogLines[j];
const FString CurrentCategory = CurrentLine.Category.ToString();
if (FilterListPtr->IsFilterEnabled(CurrentCategory, CurrentLine.Verbosity))
{
OutEntriesCached[CachedLogIndex].CachedEntries.Add(CurrentEntry);
bAddedEntry = true;
break;
}
}
}
if (bAddedEntry)
{
continue;
}
for (int32 j = 0; j < CurrentEntry->ElementsToDraw.Num(); ++j)
{
const FString CurrentCategory = CurrentEntry->ElementsToDraw[j].Category.ToString();
FVisLogEntry::FElementToDraw &CurrentElement = CurrentEntry->ElementsToDraw[j];
if (CurrentElement.Category != NAME_None && (FilterListPtr->IsFilterEnabled(CurrentCategory, CurrentElement.Verbosity)))
{
OutEntriesCached[CachedLogIndex].CachedEntries.AddUnique(CurrentEntry);
bAddedEntry = true;
break;
}
}
if (bAddedEntry)
{
continue;
}
for (int32 SampleIndex = 0; SampleIndex < CurrentEntry->HistogramSamples.Num(); ++SampleIndex)
{
const FVisLogEntry::FHistogramSample &CurrentSample = CurrentEntry->HistogramSamples[SampleIndex];
const FName CurrentCategory = CurrentSample.Category;
const FName CurrentDataName = CurrentSample.DataName;
const bool bCurrentCategoryPassed = FilterListPtr->IsFilterEnabled(CurrentCategory.ToString(), ELogVerbosity::All);
const bool bCurrentDataNamePassed = FilterListPtr->IsFilterEnabled(CurrentDataName.ToString(), ELogVerbosity::All);
if (CurrentCategory != NAME_None && (bCurrentCategoryPassed && bCurrentDataNamePassed))
{
OutEntriesCached[CachedLogIndex].CachedEntries.AddUnique(CurrentEntry);
bAddedEntry = true;
break;
}
}
if (bAddedEntry)
{
continue;
}
for (const auto CurrentData : CurrentEntry->DataBlocks)
{
const bool bCurrentCategoryPassed = FilterListPtr->IsFilterEnabled(CurrentData.Category.ToString(), ELogVerbosity::All);
const bool bCurrentTagNamePassed = FilterListPtr->IsFilterEnabled(CurrentData.TagName.ToString(), ELogVerbosity::All);
if (CurrentData.TagName != NAME_None && (bCurrentCategoryPassed && bCurrentTagNamePassed))
{
OutEntriesCached[CachedLogIndex].CachedEntries.AddUnique(CurrentEntry);
bAddedEntry = true;
break;
}
}
}
}
else
{
// if there is no LogFilter widget - show all
OutEntriesCached[CachedLogIndex].CachedEntries = Log->Entries;
}
}
OutEntries.Reset();
if (QuickFilterText.Len() > 0)
{
// filter our data using quick filter string
const int32 NumEntries = OutEntriesCached[CachedLogIndex].CachedEntries.Num();
for (int32 Index = 0; Index < NumEntries; ++Index)
{
TSharedPtr<FVisLogEntry> LogEntry = OutEntriesCached[CachedLogIndex].CachedEntries[Index];
if (!LogEntry.IsValid())
{
continue;
}
bool bAddedEntry = false;
if (!bAddedEntry)
{
for (int32 LineIndex = 0; LineIndex < LogEntry->LogLines.Num(); ++LineIndex)
{
FString CurrentCategory = LogEntry->LogLines[LineIndex].Category.ToString();
if (bHistogramGraphsFilter || CurrentCategory.Find(QuickFilterText) != INDEX_NONE)
{
OutEntries.AddUnique(LogEntry);
bAddedEntry = true;
break;
}
}
}
if (bAddedEntry)
{
continue;
}
for (int32 ElementIndex = 0; ElementIndex < LogEntry->ElementsToDraw.Num(); ++ElementIndex)
{
FString CurrentCategory = LogEntry->ElementsToDraw[ElementIndex].Category.ToString();
if (bHistogramGraphsFilter || CurrentCategory.Find(QuickFilterText) != INDEX_NONE)
{
OutEntries.AddUnique(LogEntry);
bAddedEntry = true;
break;
}
}
if (bAddedEntry)
{
continue;
}
for (int32 SampleIndex = 0; SampleIndex < LogEntry->HistogramSamples.Num(); ++SampleIndex)
{
const FName CurrentCategory = LogEntry->HistogramSamples[SampleIndex].Category;
const FName CurrentGraphName = LogEntry->HistogramSamples[SampleIndex].GraphName;
const FName CurrentDataName = LogEntry->HistogramSamples[SampleIndex].DataName;
const bool bCurrentCategoryPassed = bHistogramGraphsFilter || (QuickFilterText.Len() == 0 || CurrentCategory.ToString().Find(QuickFilterText) != INDEX_NONE);
const bool bCurrentDataNamePassed = !bHistogramGraphsFilter || (QuickFilterText.Len() == 0 || CurrentDataName.ToString().Find(QuickFilterText) != INDEX_NONE);
if (bCurrentCategoryPassed && bCurrentDataNamePassed)
{
OutEntries.AddUnique(LogEntry);
bAddedEntry = true;
break;
}
}
if (bAddedEntry)
{
continue;
}
for (const auto CurrentData : LogEntry->DataBlocks)
{
const bool bCurrentCategoryPassed = bHistogramGraphsFilter || (QuickFilterText.Len() == 0 || CurrentData.Category.ToString().Find(QuickFilterText) != INDEX_NONE);
const bool bCurrentTagNamePassed = !bHistogramGraphsFilter || (QuickFilterText.Len() == 0 || CurrentData.TagName.ToString().Find(QuickFilterText) != INDEX_NONE);
if (bCurrentCategoryPassed && bCurrentTagNamePassed)
{
OutEntries.AddUnique(LogEntry);
bAddedEntry = true;
break;
}
}
} //for (int32 Index = 0; Index < NumEntries; ++Index)
} //if (QuickFilterText.Len() > 0)
else
{
OutEntries = OutEntriesCached[CachedLogIndex].CachedEntries;
}
}
void SLogVisualizer::OnLogCategoryFiltersChanged()
{
LogsList.Reset();
OutEntriesCached.Reset();
RebuildFilteredList();
Merging using UE4-Fortnite-To-UE4 up to CL 2082758 Includes following engine CLs: CL 2080462: Added verbosity selection to category filters in Log Visualizer window CL 2081939: Fixed crash in Log Visualizer and missing entry on timeline with log containing only 2 entries. CL 2082118: Fixes and improovements for VisLogs - fixed logs visualization for logs with only one entry (Log Visualizer window) - fixed logs spam about missing json field (Log Visualizer window) - fixed crash with categories in Log Visualization window - added category and verbosity serialization for vislog shape elements (vlog files) CL 2080253: Added categories to VisLog shapes CL 2081762: Fixes to Log Visualizer. Logs without any log lines but with geometry elements are set on timeline properly. CL 2081859: Added double click to Log Visualizer action, to move editor camera to view current log location CL 2080159: Gameply Tag Pin now only allows single select #TTP 335383 - Editor: GameplayTag Pin should only allow a single selection #proj UE4 #change Removes all other tags from the correct container when in single select mode, was a missed variable change from a previous TTP CL 2081306: Made changes to navigation filters that allow for usage of virtual verstion dtQueryFilter #UE4 The scary part here is that having a dtQueryFilter contan a vftable was messing up FRecastQueryFilter's vftable it was getting from INavigationQueryFilterInterface. Reversing order of parent clas declaration of FRecastQueryFilter fixed the issue, but it's scary and looks like a compiler issue. [CL 2088758 by Billy Bramer in Main branch]
2014-05-29 17:46:51 -04:00
if (LogVisualizer && LogVisualizer->Logs.IsValidIndex(SelectedLogIndex))
{
TSharedPtr<FActorsVisLog> Log = LogVisualizer->Logs[SelectedLogIndex];
if (Log.IsValid() && Log->Entries.IsValidIndex(LogEntryIndex))
Merging using UE4-Fortnite-To-UE4 up to CL 2082758 Includes following engine CLs: CL 2080462: Added verbosity selection to category filters in Log Visualizer window CL 2081939: Fixed crash in Log Visualizer and missing entry on timeline with log containing only 2 entries. CL 2082118: Fixes and improovements for VisLogs - fixed logs visualization for logs with only one entry (Log Visualizer window) - fixed logs spam about missing json field (Log Visualizer window) - fixed crash with categories in Log Visualization window - added category and verbosity serialization for vislog shape elements (vlog files) CL 2080253: Added categories to VisLog shapes CL 2081762: Fixes to Log Visualizer. Logs without any log lines but with geometry elements are set on timeline properly. CL 2081859: Added double click to Log Visualizer action, to move editor camera to view current log location CL 2080159: Gameply Tag Pin now only allows single select #TTP 335383 - Editor: GameplayTag Pin should only allow a single selection #proj UE4 #change Removes all other tags from the correct container when in single select mode, was a missed variable change from a previous TTP CL 2081306: Made changes to navigation filters that allow for usage of virtual verstion dtQueryFilter #UE4 The scary part here is that having a dtQueryFilter contan a vftable was messing up FRecastQueryFilter's vftable it was getting from INavigationQueryFilterInterface. Reversing order of parent clas declaration of FRecastQueryFilter fixed the issue, but it's scary and looks like a compiler issue. [CL 2088758 by Billy Bramer in Main branch]
2014-05-29 17:46:51 -04:00
{
ShowEntry(Log->Entries[LogEntryIndex].Get());
}
}
InvalidateCanvas();
}
UWorld* SLogVisualizer::GetWorld() const
{
// TODO: This needs to be an internalized reference
UEditorEngine *EEngine = Cast<UEditorEngine>(GEngine);
if (GIsEditor && EEngine != NULL)
{
// lets use PlayWorld during PIE/Simulate and regular world from editor otherwise, to draw debug information
return EEngine->PlayWorld != NULL ? EEngine->PlayWorld : EEngine->GetEditorWorldContext().World();
}
else if (!GIsEditor)
{
return LogVisualizer->GetWorld();
}
return NULL;
}
void SLogVisualizer::Tick( const FGeometry& AllottedGeometry, const double InCurrentTime, const float InDeltaTime )
{
SCompoundWidget::Tick(AllottedGeometry, InCurrentTime, InDeltaTime);
TimeTillNextUpdate -= InDeltaTime;
UWorld* World = GetWorld();
if (World && !World->bPlayersOnly && TimeTillNextUpdate < 0 && LogVisualizer->IsRecording())
{
DoTickUpdate();
//DoFullUpdate();
}
if (bStickToLastData && World && !World->bPlayersOnly && LogVisualizer->IsRecording() && World->IsGameWorld() && LogVisualizer && LogVisualizer->Logs.IsValidIndex(SelectedLogIndex))
{
TSharedPtr<FActorsVisLog> Log = LogVisualizer->Logs[SelectedLogIndex];
if (Log->Entries.Num() > 0 && LogEntryIndex != Log->Entries.Num() - 1)
{
LogEntryIndex = Log->Entries.Num() - 1;
ShowEntry(Log->Entries[LogEntryIndex].Get());
}
}
}
FReply SLogVisualizer::OnMouseWheel( const FGeometry& MyGeometry, const FPointerEvent& MouseEvent )
{
if (MouseEvent.IsLeftControlDown())
{
OnSetZoomValue(FMath::Clamp(ZoomSliderValue + MouseEvent.GetWheelDelta() * 0.05f, 0.f, 1.f));
return FReply::Handled();
}
if (MouseEvent.IsLeftShiftDown())
{
OnSetHistogramWindowValue(MouseEvent.GetWheelDelta());
return FReply::Handled();
}
return SCompoundWidget::OnMouseWheel(MyGeometry, MouseEvent);
}
FReply SLogVisualizer::OnKeyDown( const FGeometry& MyGeometry, const FKeyboardEvent& InKeyboardEvent )
{
const FKey Key = InKeyboardEvent.GetKey();
if (Key == EKeys::Left || Key == EKeys::Right)
{
int32 MoveBy = Key == EKeys::Left ? -1 : 1;
if (InKeyboardEvent.IsLeftControlDown())
{
MoveBy *= 10;
}
IncrementCurrentLogIndex(MoveBy);
return FReply::Handled();
}
return SCompoundWidget::OnKeyDown(MyGeometry, InKeyboardEvent);
}
TSharedRef< SWidget > SLogVisualizer::MakeMainMenu()
{
FMenuBarBuilder MenuBuilder( NULL );
{
// File
MenuBuilder.AddPullDownMenu(
NSLOCTEXT("LogVisualizer", "FileMenu", "File"),
NSLOCTEXT("LogVisualizer", "FileMenu_ToolTip", "Open the file menu"),
FNewMenuDelegate::CreateSP( this, &SLogVisualizer::OpenSavedSession ) );
// Help
MenuBuilder.AddPullDownMenu(
NSLOCTEXT("LogVisualizer", "HelpMenu", "Help"),
NSLOCTEXT("LogVisualizer", "HelpMenu_ToolTip", "Open the help menu"),
FNewMenuDelegate::CreateSP( this, &SLogVisualizer::FillHelpMenu ) );
}
// Create the menu bar
TSharedRef< SWidget > MenuBarWidget = MenuBuilder.MakeWidget();
return MenuBarWidget;
}
void SLogVisualizer::FillHelpMenu(FMenuBuilder& MenuBuilder)
{
}
void SLogVisualizer::OpenSavedSession(FMenuBuilder& MenuBuilder)
{
}
//----------------------------------------------------------------------//
// non-slate
//----------------------------------------------------------------------//
void SLogVisualizer::SelectionChanged(AActor* DebuggedActor, bool bIsBeingDebuggedNow)
{
if (DebuggedActor != NULL && bIsBeingDebuggedNow)
{
SelectActor(DebuggedActor);
}
}
void SLogVisualizer::IncrementCurrentLogIndex(int32 IncrementBy)
{
Merging using UE4-Fortnite-To-UE4 up to CL 2082758 Includes following engine CLs: CL 2080462: Added verbosity selection to category filters in Log Visualizer window CL 2081939: Fixed crash in Log Visualizer and missing entry on timeline with log containing only 2 entries. CL 2082118: Fixes and improovements for VisLogs - fixed logs visualization for logs with only one entry (Log Visualizer window) - fixed logs spam about missing json field (Log Visualizer window) - fixed crash with categories in Log Visualization window - added category and verbosity serialization for vislog shape elements (vlog files) CL 2080253: Added categories to VisLog shapes CL 2081762: Fixes to Log Visualizer. Logs without any log lines but with geometry elements are set on timeline properly. CL 2081859: Added double click to Log Visualizer action, to move editor camera to view current log location CL 2080159: Gameply Tag Pin now only allows single select #TTP 335383 - Editor: GameplayTag Pin should only allow a single selection #proj UE4 #change Removes all other tags from the correct container when in single select mode, was a missed variable change from a previous TTP CL 2081306: Made changes to navigation filters that allow for usage of virtual verstion dtQueryFilter #UE4 The scary part here is that having a dtQueryFilter contan a vftable was messing up FRecastQueryFilter's vftable it was getting from INavigationQueryFilterInterface. Reversing order of parent clas declaration of FRecastQueryFilter fixed the issue, but it's scary and looks like a compiler issue. [CL 2088758 by Billy Bramer in Main branch]
2014-05-29 17:46:51 -04:00
if (!LogVisualizer->Logs.IsValidIndex(SelectedLogIndex))
{
return;
}
TSharedPtr<FActorsVisLog> Log = LogVisualizer->Logs[SelectedLogIndex];
check(Log.IsValid());
int32 NewEntryIndex = FMath::Clamp(LogEntryIndex + IncrementBy, 0, Log->Entries.Num() - 1);
if (FilterListPtr.IsValid())
{
while (NewEntryIndex >= 0 && NewEntryIndex < Log->Entries.Num())
{
Merging using UE4-Fortnite-To-UE4 up to CL 2082758 Includes following engine CLs: CL 2080462: Added verbosity selection to category filters in Log Visualizer window CL 2081939: Fixed crash in Log Visualizer and missing entry on timeline with log containing only 2 entries. CL 2082118: Fixes and improovements for VisLogs - fixed logs visualization for logs with only one entry (Log Visualizer window) - fixed logs spam about missing json field (Log Visualizer window) - fixed crash with categories in Log Visualization window - added category and verbosity serialization for vislog shape elements (vlog files) CL 2080253: Added categories to VisLog shapes CL 2081762: Fixes to Log Visualizer. Logs without any log lines but with geometry elements are set on timeline properly. CL 2081859: Added double click to Log Visualizer action, to move editor camera to view current log location CL 2080159: Gameply Tag Pin now only allows single select #TTP 335383 - Editor: GameplayTag Pin should only allow a single selection #proj UE4 #change Removes all other tags from the correct container when in single select mode, was a missed variable change from a previous TTP CL 2081306: Made changes to navigation filters that allow for usage of virtual verstion dtQueryFilter #UE4 The scary part here is that having a dtQueryFilter contan a vftable was messing up FRecastQueryFilter's vftable it was getting from INavigationQueryFilterInterface. Reversing order of parent clas declaration of FRecastQueryFilter fixed the issue, but it's scary and looks like a compiler issue. [CL 2088758 by Billy Bramer in Main branch]
2014-05-29 17:46:51 -04:00
bool bShouldShow = false;
for (int32 LineIndex = 0; LineIndex < Log->Entries[NewEntryIndex]->LogLines.Num(); ++LineIndex)
{
if (FilterListPtr->IsFilterEnabled(Log->Entries[NewEntryIndex]->LogLines[LineIndex].Category.ToString(), Log->Entries[NewEntryIndex]->LogLines[LineIndex].Verbosity))
{
Merging using UE4-Fortnite-To-UE4 up to CL 2082758 Includes following engine CLs: CL 2080462: Added verbosity selection to category filters in Log Visualizer window CL 2081939: Fixed crash in Log Visualizer and missing entry on timeline with log containing only 2 entries. CL 2082118: Fixes and improovements for VisLogs - fixed logs visualization for logs with only one entry (Log Visualizer window) - fixed logs spam about missing json field (Log Visualizer window) - fixed crash with categories in Log Visualization window - added category and verbosity serialization for vislog shape elements (vlog files) CL 2080253: Added categories to VisLog shapes CL 2081762: Fixes to Log Visualizer. Logs without any log lines but with geometry elements are set on timeline properly. CL 2081859: Added double click to Log Visualizer action, to move editor camera to view current log location CL 2080159: Gameply Tag Pin now only allows single select #TTP 335383 - Editor: GameplayTag Pin should only allow a single selection #proj UE4 #change Removes all other tags from the correct container when in single select mode, was a missed variable change from a previous TTP CL 2081306: Made changes to navigation filters that allow for usage of virtual verstion dtQueryFilter #UE4 The scary part here is that having a dtQueryFilter contan a vftable was messing up FRecastQueryFilter's vftable it was getting from INavigationQueryFilterInterface. Reversing order of parent clas declaration of FRecastQueryFilter fixed the issue, but it's scary and looks like a compiler issue. [CL 2088758 by Billy Bramer in Main branch]
2014-05-29 17:46:51 -04:00
bShouldShow = true;
break;
}
}
if (!bShouldShow)
Merging using UE4-Fortnite-To-UE4 up to CL 2082758 Includes following engine CLs: CL 2080462: Added verbosity selection to category filters in Log Visualizer window CL 2081939: Fixed crash in Log Visualizer and missing entry on timeline with log containing only 2 entries. CL 2082118: Fixes and improovements for VisLogs - fixed logs visualization for logs with only one entry (Log Visualizer window) - fixed logs spam about missing json field (Log Visualizer window) - fixed crash with categories in Log Visualization window - added category and verbosity serialization for vislog shape elements (vlog files) CL 2080253: Added categories to VisLog shapes CL 2081762: Fixes to Log Visualizer. Logs without any log lines but with geometry elements are set on timeline properly. CL 2081859: Added double click to Log Visualizer action, to move editor camera to view current log location CL 2080159: Gameply Tag Pin now only allows single select #TTP 335383 - Editor: GameplayTag Pin should only allow a single selection #proj UE4 #change Removes all other tags from the correct container when in single select mode, was a missed variable change from a previous TTP CL 2081306: Made changes to navigation filters that allow for usage of virtual verstion dtQueryFilter #UE4 The scary part here is that having a dtQueryFilter contan a vftable was messing up FRecastQueryFilter's vftable it was getting from INavigationQueryFilterInterface. Reversing order of parent clas declaration of FRecastQueryFilter fixed the issue, but it's scary and looks like a compiler issue. [CL 2088758 by Billy Bramer in Main branch]
2014-05-29 17:46:51 -04:00
{
for (int32 LineIndex = 0; LineIndex < Log->Entries[NewEntryIndex]->ElementsToDraw.Num(); ++LineIndex)
{
if (Log->Entries[NewEntryIndex]->ElementsToDraw[LineIndex].Category == NAME_None || FilterListPtr->IsFilterEnabled(Log->Entries[NewEntryIndex]->ElementsToDraw[LineIndex].Category.ToString(), Log->Entries[NewEntryIndex]->ElementsToDraw[LineIndex].Verbosity))
{
bShouldShow = true;
break;
}
}
}
if (!bShouldShow)
{
for (int32 SampleIndex = 0; SampleIndex < Log->Entries[NewEntryIndex]->HistogramSamples.Num(); ++SampleIndex)
{
const FName CurrentCategory = Log->Entries[NewEntryIndex]->HistogramSamples[SampleIndex].Category;
const FName CurrentGraphName = Log->Entries[NewEntryIndex]->HistogramSamples[SampleIndex].GraphName;
const FName CurrentDataName = Log->Entries[NewEntryIndex]->HistogramSamples[SampleIndex].DataName;
if (CurrentCategory == NAME_None ||
(FilterListPtr->IsFilterEnabled(CurrentCategory.ToString(), ELogVerbosity::All) && FilterListPtr->IsFilterEnabled(CurrentGraphName.ToString(), CurrentDataName.ToString(), ELogVerbosity::All)))
{
bShouldShow = true;
break;
}
}
}
if (!bShouldShow)
{
for (const auto CurrentData : Log->Entries[NewEntryIndex]->DataBlocks)
{
const FName CurrentCategory = CurrentData.Category;
const FName CurrentTagName = CurrentData.TagName;
if (CurrentCategory == NAME_None ||
(FilterListPtr->IsFilterEnabled(CurrentCategory.ToString(), ELogVerbosity::All) && FilterListPtr->IsFilterEnabled(CurrentTagName.ToString(), ELogVerbosity::All)))
{
bShouldShow = true;
break;
}
}
}
Merging using UE4-Fortnite-To-UE4 up to CL 2082758 Includes following engine CLs: CL 2080462: Added verbosity selection to category filters in Log Visualizer window CL 2081939: Fixed crash in Log Visualizer and missing entry on timeline with log containing only 2 entries. CL 2082118: Fixes and improovements for VisLogs - fixed logs visualization for logs with only one entry (Log Visualizer window) - fixed logs spam about missing json field (Log Visualizer window) - fixed crash with categories in Log Visualization window - added category and verbosity serialization for vislog shape elements (vlog files) CL 2080253: Added categories to VisLog shapes CL 2081762: Fixes to Log Visualizer. Logs without any log lines but with geometry elements are set on timeline properly. CL 2081859: Added double click to Log Visualizer action, to move editor camera to view current log location CL 2080159: Gameply Tag Pin now only allows single select #TTP 335383 - Editor: GameplayTag Pin should only allow a single selection #proj UE4 #change Removes all other tags from the correct container when in single select mode, was a missed variable change from a previous TTP CL 2081306: Made changes to navigation filters that allow for usage of virtual verstion dtQueryFilter #UE4 The scary part here is that having a dtQueryFilter contan a vftable was messing up FRecastQueryFilter's vftable it was getting from INavigationQueryFilterInterface. Reversing order of parent clas declaration of FRecastQueryFilter fixed the issue, but it's scary and looks like a compiler issue. [CL 2088758 by Billy Bramer in Main branch]
2014-05-29 17:46:51 -04:00
if (bShouldShow)
{
break;
}
NewEntryIndex += (IncrementBy > 0 ? 1 : -1);
}
}
if (NewEntryIndex != LogEntryIndex && Log->Entries.IsValidIndex(NewEntryIndex))
{
LogEntryIndex = NewEntryIndex;
ShowEntry(Log->Entries[NewEntryIndex].Get());
}
}
void SLogVisualizer::AddOrUpdateLog(int32 LogIndex, const FActorsVisLog* Log)
{
if (Log->Entries.Num() == 0)
{
return;
}
if (LogsList.Num() == 0)
{
Timeline->SetVisibility(EVisibility::Visible);
ScrollBar->SetVisibility(EVisibility::Visible);
ZoomSlider->SetVisibility(EVisibility::Visible);
}
const float StartTimestamp = Log->Entries[0]->TimeStamp;
const float EndTimestamp = Log->Entries[Log->Entries.Num() - 1]->TimeStamp;
int32 CurrentIndex = INDEX_NONE;
int32 LogListNum = LogsList.Num();
for (int32 ListIndex = 0; ListIndex < LogListNum; ++ListIndex)
{
if (LogsList[ListIndex]->LogIndex == LogIndex)
{
CurrentIndex = ListIndex;
break;
}
}
// add used categories
for (int32 EntryIndex = 0; EntryIndex < Log->Entries.Num(); ++EntryIndex)
{
if (CurrentIndex != INDEX_NONE && Log->Entries[EntryIndex]->TimeStamp <= LogsList[CurrentIndex]->EndTimestamp)
{
continue;
}
for (auto Iter(Log->Entries[EntryIndex]->LogLines.CreateConstIterator()); Iter; Iter++)
{
int32 Index = UsedCategories.Find(Iter->Category.ToString());
if (Index == INDEX_NONE)
{
Index = UsedCategories.Add(Iter->Category.ToString());
FilterListPtr->AddFilter(Iter->Category.ToString(), GetColorForUsedCategory(Index));
}
}
Merging using UE4-Fortnite-To-UE4 up to CL 2082758 Includes following engine CLs: CL 2080462: Added verbosity selection to category filters in Log Visualizer window CL 2081939: Fixed crash in Log Visualizer and missing entry on timeline with log containing only 2 entries. CL 2082118: Fixes and improovements for VisLogs - fixed logs visualization for logs with only one entry (Log Visualizer window) - fixed logs spam about missing json field (Log Visualizer window) - fixed crash with categories in Log Visualization window - added category and verbosity serialization for vislog shape elements (vlog files) CL 2080253: Added categories to VisLog shapes CL 2081762: Fixes to Log Visualizer. Logs without any log lines but with geometry elements are set on timeline properly. CL 2081859: Added double click to Log Visualizer action, to move editor camera to view current log location CL 2080159: Gameply Tag Pin now only allows single select #TTP 335383 - Editor: GameplayTag Pin should only allow a single selection #proj UE4 #change Removes all other tags from the correct container when in single select mode, was a missed variable change from a previous TTP CL 2081306: Made changes to navigation filters that allow for usage of virtual verstion dtQueryFilter #UE4 The scary part here is that having a dtQueryFilter contan a vftable was messing up FRecastQueryFilter's vftable it was getting from INavigationQueryFilterInterface. Reversing order of parent clas declaration of FRecastQueryFilter fixed the issue, but it's scary and looks like a compiler issue. [CL 2088758 by Billy Bramer in Main branch]
2014-05-29 17:46:51 -04:00
for (auto Iter(Log->Entries[EntryIndex]->ElementsToDraw.CreateConstIterator()); Iter; Iter++)
{
const FString CategoryAsString = Iter->Category != NAME_None ? Iter->Category.ToString() : TEXT("ShapeElement");
int32 Index = UsedCategories.Find(CategoryAsString);
if (Index == INDEX_NONE)
{
Index = UsedCategories.Add(CategoryAsString);
FilterListPtr->AddFilter(CategoryAsString, GetColorForUsedCategory(Index));
}
}
for (int32 SampleIndex = 0; SampleIndex < Log->Entries[EntryIndex]->HistogramSamples.Num(); ++SampleIndex)
{
const FString CategoryAsString = Log->Entries[EntryIndex]->HistogramSamples[SampleIndex].Category.ToString();
int32 Index = UsedCategories.Find(CategoryAsString);
if (Index == INDEX_NONE)
{
Index = UsedCategories.Add(CategoryAsString);
FilterListPtr->AddFilter(CategoryAsString, GetColorForUsedCategory(Index));
}
const FString GraphNameAsString = Log->Entries[EntryIndex]->HistogramSamples[SampleIndex].GraphName.ToString();
const FString DataNameAsString = Log->Entries[EntryIndex]->HistogramSamples[SampleIndex].DataName.ToString();
FilterListPtr->AddGraphFilter(GraphNameAsString, DataNameAsString, FColor::White);
}
for (const auto CurrentData : Log->Entries[EntryIndex]->DataBlocks)
{
int32 Index = UsedCategories.Find(CurrentData.Category.ToString());
if (Index == INDEX_NONE)
{
Index = UsedCategories.Add(CurrentData.Category.ToString());
FilterListPtr->AddFilter(CurrentData.Category.ToString(), GetColorForUsedCategory(Index));
}
}
}
if (CurrentIndex == INDEX_NONE)
{
LogsList.Add(MakeShareable(new FLogsListItem(Log->Name.ToString(), StartTimestamp, EndTimestamp, LogIndex)));
}
else
{
LogsList[CurrentIndex]->StartTimestamp = StartTimestamp;
LogsList[CurrentIndex]->LastEndTimestamp = LogsList[CurrentIndex]->EndTimestamp;
LogsList[CurrentIndex]->EndTimestamp= EndTimestamp;
}
}
void SLogVisualizer::DoFullUpdate()
{
TSharedPtr<FLogsListItem>* LogListItem = LogsList.GetTypedData();
for (int32 ItemIndex = 0; ItemIndex < LogsList.Num(); ++ItemIndex, ++LogListItem)
{
if (LogListItem->IsValid() && LogVisualizer->Logs.IsValidIndex((*LogListItem)->LogIndex))
{
TSharedPtr<FActorsVisLog>& Log = LogVisualizer->Logs[(*LogListItem)->LogIndex];
if (Log->Entries.Num() > 0)
{
LogsStartTime = FMath::Min(Log->Entries[0]->TimeStamp, LogsStartTime);
LogsEndTime = FMath::Max(Log->Entries[Log->Entries.Num() - 1]->TimeStamp, LogsEndTime);
}
}
}
Timeline->SetMinMaxValues(LogsStartTime, LogsEndTime);
// set zoom max so that single even on SBarLogs has desired size on maximum zoom
const float WidthPx = Timeline->GetDrawingGeometry().Size.X;
if (WidthPx > 0)
{
const float OldMaxZoom = MaxZoom;
const float PxPerTimeUnit = WidthPx * SLogBar::TimeUnit / (LogsEndTime - LogsStartTime);
MaxZoom = SLogBar::MaxUnitSizePx / PxPerTimeUnit;
if (MaxZoom < MinZoom)
{
MaxZoom = MinZoom;
}
ZoomSliderValue = MaxZoom * ZoomSliderValue / OldMaxZoom;
// update
}
LogsList.Reset();
OutEntriesCached.Reset();
RebuildFilteredList();
TimeTillNextUpdate = 1.f / FullUpdateFrequency;
InvalidateCanvas();
}
void SLogVisualizer::DoTickUpdate()
{
TSharedPtr<FLogsListItem>* LogListItem = LogsList.GetTypedData();
for (int32 ItemIndex = 0; ItemIndex < LogsList.Num(); ++ItemIndex, ++LogListItem)
{
if (LogListItem->IsValid() && LogVisualizer->Logs.IsValidIndex((*LogListItem)->LogIndex))
{
TSharedPtr<FActorsVisLog>& Log = LogVisualizer->Logs[(*LogListItem)->LogIndex];
if (Log->Entries.Num() > 0)
{
LogsStartTime = FMath::Min(Log->Entries[0]->TimeStamp, LogsStartTime);
LogsEndTime = FMath::Max(Log->Entries[Log->Entries.Num() - 1]->TimeStamp, LogsEndTime);
}
}
}
Timeline->SetMinMaxValues(LogsStartTime, LogsEndTime);
// set zoom max so that single even on SBarLogs has desired size on maximum zoom
const float WidthPx = Timeline->GetDrawingGeometry().Size.X;
if (WidthPx > 0)
{
const float OldMaxZoom = MaxZoom;
const float PxPerTimeUnit = WidthPx * SLogBar::TimeUnit / (LogsEndTime - LogsStartTime);
MaxZoom = SLogBar::MaxUnitSizePx / PxPerTimeUnit;
if (MaxZoom < MinZoom)
{
MaxZoom = MinZoom;
}
ZoomSliderValue = MaxZoom * ZoomSliderValue / OldMaxZoom;
// update
}
RebuildFilteredList();
TimeTillNextUpdate = 1.f / FullUpdateFrequency;
InvalidateCanvas();
}
void SLogVisualizer::OnLogAdded()
{
// take last log
const int32 NewLogIndex = LogVisualizer->Logs.Num()-1;
TSharedPtr<FLogsListItem> Item;
for (int32 Index = 0; Index < LogsList.Num(); ++Index)
{
Item = LogsList[Index];
TArray<TSharedPtr<FActorsVisLog> >& Logs = LogVisualizer->Logs;
if (Item->Name == Logs[NewLogIndex]->Name.ToString())
{
break;
}
}
if (!Item.IsValid())
{
AddOrUpdateLog(NewLogIndex, LogVisualizer->Logs[NewLogIndex].Get());
}
RequestFullUpdate();
}
TSharedRef<ITableRow> SLogVisualizer::LogsListGenerateRow(TSharedPtr<FLogsListItem> InItem, const TSharedRef<STableViewBase>& OwnerTable)
{
return SNew(SLogsTableRow, OwnerTable)
.Item(InItem)
.OwnerVisualizerWidget(SharedThis(this));
}
void SLogVisualizer::LogsListSelectionChanged(TSharedPtr<FLogsListItem> SelectedItem, ESelectInfo::Type SelectInfo)
{
//@todo find log entry closest to current time selection
//LogEntryIndex = INDEX_NONE;
const int32 NewLogIndex = SelectedItem.IsValid() ? SelectedItem->LogIndex : INDEX_NONE;
if (NewLogIndex != SelectedLogIndex && NewLogIndex != INDEX_NONE)
{
SelectedLogIndex = NewLogIndex;
if (LogVisualizer->Logs.IsValidIndex(NewLogIndex))
{
TSharedPtr<FActorsVisLog> Log = LogVisualizer->Logs[NewLogIndex];
LogEntryIndex = Log->Entries.Num() - 1;
}
}
if (LogVisualizer->Logs.IsValidIndex(SelectedLogIndex))
{
if (USelection* SelectedActors = GEditor->GetSelectedActors())
{
TSharedPtr<FActorsVisLog> Log = LogVisualizer->Logs[SelectedLogIndex];
if (UWorld* World = GetWorld())
{
for (FConstPawnIterator Iterator = World->GetPawnIterator(); Iterator; ++Iterator)
{
if (APawn* CurrentPawn = *Iterator)
{
if (AController* CurrentController = CurrentPawn->GetController())
{
if (CurrentController->GetName() == Log->Name.ToString())
{
SelectedActors->Select(CurrentPawn);
}
else
{
SelectedActors->Deselect(CurrentPawn);
}
}
}
}
}
}
}
//SetCurrentViewedTime(CurrentViewedTime, /*bForce=*/true);
LogsLinesWidget->RequestListRefresh();
InvalidateCanvas();
}
TSharedRef<ITableRow> SLogVisualizer::LogEntryLinesGenerateRow(TSharedPtr<FLogEntryItem> Item, const TSharedRef<STableViewBase>& OwnerTable)
{
return SNew( STableRow< TSharedPtr<FString> >, OwnerTable )
[
SNew(SHorizontalBox)
+SHorizontalBox::Slot()
.AutoWidth()
.Padding(FMargin(5.0f, 0.0f))
[
SNew(STextBlock)
.ColorAndOpacity(FSlateColor(Item->CategoryColor))
.Text(Item->Category)
]
+SHorizontalBox::Slot()
.AutoWidth()
.Padding(FMargin(5.0f, 0.0f))
[
SNew(STextBlock)
.ColorAndOpacity(FSlateColor(FLinearColor::Gray))
.Text(FString(TEXT("(")) + FString(FOutputDevice::VerbosityToString(Item->Verbosity)) + FString(TEXT(")")))
]
+SHorizontalBox::Slot()
.AutoWidth()
.Padding(FMargin(5.0f, 0.0f))
[
SNew(STextBlock)
.Text(Item->Line)
]
];
}
void SLogVisualizer::LogEntryLineSelectionChanged(TSharedPtr<FLogEntryItem> SelectedItem, ESelectInfo::Type SelectInfo)
{
TMap<FName, FVisualLogExtensionInterface*>& AllExtensions = FVisualLog::Get().GetAllExtensions();
for (auto Iterator = AllExtensions.CreateIterator(); Iterator; ++Iterator)
{
FVisualLogExtensionInterface* Extension = (*Iterator).Value;
if (Extension != NULL)
{
if (SelectedItem.IsValid() == true)
{
Extension->LogEntryLineSelectionChanged(SelectedItem, SelectedItem->UserData, SelectedItem->TagName);
}
else
{
Extension->LogEntryLineSelectionChanged(SelectedItem, 0, NAME_None);
}
}
}
}
bool SLogVisualizer::ShouldListLog(const TSharedPtr<FActorsVisLog>& Log)
{
//// Check log name filter
if (!Log.IsValid() || (LogNameFilterString.Len() > 0 && !Log->Name.ToString().Contains(LogNameFilterString)))
{
return false;
}
UWorld* World = GetWorld();
if (!World || World->IsGameWorld())
{
return !bIgnoreTrivialLogs || Log->Entries.Num() >= 2;
}
else
{
static TArray<TSharedPtr<FVisLogEntry> > OutEntries;
GetVisibleEntries(Log, OutEntries);
return !bIgnoreTrivialLogs || OutEntries.Num() >= 2;
}
return true;
}
void SLogVisualizer::UpdateFilterInfo()
{
// get filters
LogNameFilterString = LogNameFilterBox->GetText().ToString();
}
void SLogVisualizer::SetCurrentViewedTime(float NewTime, const bool bForce)
{
if (CurrentViewedTime == NewTime && bForce == false)
{
return;
}
CurrentViewedTime = NewTime;
InvalidateCanvas();
}
void SLogVisualizer::InvalidateCanvas()
{
#if WITH_EDITOR
UEditorEngine *EEngine = Cast<UEditorEngine>(GEngine);
if (GIsEditor && EEngine != NULL)
{
for (int32 Index = 0; Index < EEngine->AllViewportClients.Num(); Index++)
{
FEditorViewportClient* ViewportClient = EEngine->AllViewportClients[Index];
if (ViewportClient)
{
ViewportClient->Invalidate();
}
}
}
#endif
}
void SLogVisualizer::RequestShowLogEntry(TSharedPtr<FLogsListItem> Item, TSharedPtr<FVisLogEntry> LogEntry)
{
ShowLogEntry(Item, LogEntry);
}
void SLogVisualizer::ShowLogEntry(TSharedPtr<FLogsListItem> Item, TSharedPtr<FVisLogEntry> LogEntry)
{
if(LogsListWidget->GetSelectedItems().Find(Item) == INDEX_NONE)
{
LogsListWidget->ClearSelection();
LogsListWidget->SetItemSelection(Item, true);
}
if (LogVisualizer->Logs.IsValidIndex(SelectedLogIndex))
{
TSharedPtr<FActorsVisLog> Log = LogVisualizer->Logs[SelectedLogIndex];
LogEntryIndex = Log->Entries.Find(LogEntry);
}
else
{
LogEntryIndex = INDEX_NONE;
}
ShowEntry(LogEntry.Get());
}
FLinearColor SLogVisualizer::GetColorForUsedCategory(int32 Index)
{
if (Index >= 0 && Index < sizeof(ColorPalette) / sizeof(ColorPalette[0]))
{
return ColorPalette[Index];
}
static bool bReateColorList = false;
static FColorList StaticColor;
if (!bReateColorList)
{
bReateColorList = true;
StaticColor.CreateColorMap();
}
return StaticColor.GetFColorByIndex(Index);
}
TSharedRef<ITableRow> SLogVisualizer::HandleGenerateLogStatus(TSharedPtr<FLogStatusItem> InItem, const TSharedRef<STableViewBase>& OwnerTable)
{
if (InItem->Children.Num() > 0)
{
return SNew(STableRow<TSharedPtr<FLogStatusItem> >, OwnerTable)
[
SNew(STextBlock).Text(InItem->ItemText)
];
}
FString TooltipText = FString::Printf(TEXT("%s: %s"), *InItem->ItemText, *InItem->ValueText);
return SNew(STableRow<TSharedPtr<FLogStatusItem> >, OwnerTable)
[
SNew(SBorder)
.BorderImage( FEditorStyle::GetBrush("NoBorder") )
.ToolTipText(TooltipText)
[
SNew(SHorizontalBox)
+SHorizontalBox::Slot()
.AutoWidth()
[
SNew(STextBlock).Text(InItem->ItemText).ColorAndOpacity(FColorList::Aquamarine)
]
+SHorizontalBox::Slot()
.Padding(4.0f, 0, 0, 0)
.AutoWidth()
[
SNew(STextBlock).Text(InItem->ValueText)
]
]
];
}
void SLogVisualizer::OnLogStatusGetChildren(TSharedPtr<FLogStatusItem> InItem, TArray< TSharedPtr<FLogStatusItem> >& OutItems)
{
OutItems = InItem->Children;
}
void SLogVisualizer::UpdateStatusItems(const FVisLogEntry* LogEntry)
{
TArray<FString> ExpandedCategories;
for (int32 ItemIndex = 0; ItemIndex < StatusItems.Num(); ItemIndex++)
{
const bool bIsExpanded = StatusItemsView->IsItemExpanded(StatusItems[ItemIndex]);
if (bIsExpanded)
{
ExpandedCategories.Add(StatusItems[ItemIndex]->ItemText);
}
}
StatusItems.Empty();
if (LogEntry)
{
FString TimestampDesc = FString::Printf(TEXT("%.2fs"), LogEntry->TimeStamp);
StatusItems.Add(MakeShareable(new FLogStatusItem(LOCTEXT("VisLogTimestamp","Time").ToString(), TimestampDesc)));
for (int32 CategoryIndex = 0; CategoryIndex < LogEntry->Status.Num(); CategoryIndex++)
{
if (LogEntry->Status[CategoryIndex].Data.Num() <= 0)
{
continue;
}
TSharedRef<FLogStatusItem> StatusItem = MakeShareable(new FLogStatusItem(LogEntry->Status[CategoryIndex].Category));
for (int32 LineIndex = 0; LineIndex < LogEntry->Status[CategoryIndex].Data.Num(); LineIndex++)
{
FString KeyDesc, ValueDesc;
const bool bHasValue = LogEntry->Status[CategoryIndex].GetDesc(LineIndex, KeyDesc, ValueDesc);
if (bHasValue)
{
StatusItem->Children.Add(MakeShareable(new FLogStatusItem(KeyDesc, ValueDesc)));
}
}
StatusItems.Add(StatusItem);
}
}
StatusItemsView->RequestTreeRefresh();
for (int32 ItemIndex = 0; ItemIndex < StatusItems.Num(); ItemIndex++)
{
for (const FString& Category : ExpandedCategories)
{
if (StatusItems[ItemIndex]->ItemText == Category)
{
StatusItemsView->SetItemExpansion(StatusItems[ItemIndex], true);
break;
}
}
}
}
void SLogVisualizer::ShowEntry(const FVisLogEntry* LogEntry)
{
UpdateStatusItems(LogEntry);
LogEntryLines.Reset();
const FVisLogEntry::FLogLine* LogLine = LogEntry->LogLines.GetTypedData();
for (int LineIndex = 0; LineIndex < LogEntry->LogLines.Num(); ++LineIndex, ++LogLine)
{
bool bShowLine = true;
if (FilterListPtr.IsValid())
{
FString CurrentCategory = LogLine->Category.ToString();
bShowLine = FilterListPtr->IsFilterEnabled(CurrentCategory, LogLine->Verbosity) && (bHistogramGraphsFilter || (QuickFilterText.Len() == 0 || CurrentCategory.Find(QuickFilterText) != INDEX_NONE));
}
if (bShowLine)
{
FLogEntryItem EntryItem;
EntryItem.Category = LogLine->Category.ToString();
int32 Index = UsedCategories.Find(EntryItem.Category);
if (Index == INDEX_NONE)
{
Index = UsedCategories.Add(EntryItem.Category);
}
EntryItem.CategoryColor = GetColorForUsedCategory(Index);
EntryItem.Verbosity = LogLine->Verbosity;
EntryItem.Line = LogLine->Line;
EntryItem.UserData = LogLine->UserData;
EntryItem.TagName = LogLine->TagName;
LogEntryLines.Add(MakeShareable(new FLogEntryItem(EntryItem)));
}
}
SetCurrentViewedTime(LogEntry->TimeStamp);
UWorld* World = GetWorld();
for (auto It = FVisualLog::Get().GetAllExtensions().CreateIterator(); It; ++It)
{
(*It).Value->OnTimestampChange(LogEntry->TimeStamp, World, FLogVisualizerModule::Get()->GetHelperActor(World));
}
InvalidateCanvas();
LogsLinesWidget->RequestListRefresh();
}
int32 SLogVisualizer::FindIndexInLogsList(const int32 LogIndex) const
{
for (int32 Index = 0; Index < LogsList.Num(); ++Index)
{
if (LogsList[Index]->LogIndex == LogIndex)
{
return Index;
}
}
return INDEX_NONE;
}
void SLogVisualizer::RebuildFilteredList()
{
// store current selection
TArray< TSharedPtr<FLogsListItem> > ItemsToSelect = LogsListWidget->GetSelectedItems();
for (int32 LogIndex = 0; LogIndex < LogVisualizer->Logs.Num(); ++LogIndex)
{
TSharedPtr<FActorsVisLog> Log = LogVisualizer->Logs[LogIndex];
if (ShouldListLog(Log))
{
// Passed filter so add to filtered results (defer sorting until end)
AddOrUpdateLog(LogIndex, Log.Get());
UpdateVisibleEntriesCache(Log, LogIndex);
}
}
// When underlying array changes, refresh list
LogsListWidget->RequestListRefresh();
LogsListWidget->RefreshList();
// redo selection
if (ItemsToSelect.Num() > 0)
{
TSharedPtr<FLogsListItem>* Item = ItemsToSelect.GetTypedData();
for (int32 ItemIndex = 0; ItemIndex < ItemsToSelect.Num(); ++ItemIndex, ++Item)
{
const int32 IndexInList = FindIndexInLogsList((*Item)->LogIndex);
if (IndexInList != INDEX_NONE)
{
LogsListWidget->SetItemSelection(LogsList[IndexInList], true);
}
}
}
}
float SLogVisualizer::GetZoomValue() const
{
return ZoomSliderValue;
}
void SLogVisualizer::OnSetZoomValue( float NewValue )
{
const float PrevZoom = GetZoom();
const float PrevVisibleRange = 1.0f / PrevZoom;
ZoomSliderValue = NewValue;
const float Zoom = GetZoom();
const float MaxOffset = GetMaxScrollOffsetFraction();
const float MaxGraphOffset = GetMaxGraphOffset();
const float ViewedTimeSpan = (LogsEndTime - LogsStartTime) / Zoom;
const float ScrollOffsetFraction = FMath::Clamp((CurrentViewedTime - LogsStartTime - ViewedTimeSpan/2) / (LogsEndTime - LogsStartTime), 0.0f, MaxOffset);
const float WidthPx = Timeline->GetDrawingGeometry().Size.X;
const float GraphOffset = MaxOffset > 0 ? (ScrollOffsetFraction / MaxOffset) * MaxGraphOffset : 0.f;
ZoomChangedNotify.Broadcast(Zoom, -GraphOffset);
ScrollBar->SetState( ScrollOffsetFraction, 1.0f / Zoom );
Timeline->SetZoom( Zoom );
Timeline->SetOffset( -GraphOffset );
ScrollbarOffset = -GraphOffset;
InvalidateCanvas();
}
void SLogVisualizer::OnZoomScrolled(float InScrollOffsetFraction)
{
if( ZoomSliderValue > 0.0f )
{
const float MaxOffset = GetMaxScrollOffsetFraction();
const float MaxGraphOffset = GetMaxGraphOffset();
InScrollOffsetFraction = FMath::Clamp( InScrollOffsetFraction, 0.0f, MaxOffset );
float GraphOffset = -( InScrollOffsetFraction / MaxOffset ) * MaxGraphOffset;
ScrollBar->SetState( InScrollOffsetFraction, 1.0f / GetZoom() );
ZoomChangedNotify.Broadcast(GetZoom(), GraphOffset);
Timeline->SetOffset( GraphOffset );
ScrollbarOffset = GraphOffset;
InvalidateCanvas();
}
}
void SLogVisualizer::OnSetHistogramWindowValue(float NewValue)
{
HistogramPreviewWindow = FMath::Clamp(HistogramPreviewWindow + NewValue * 1.0f, 0.0f, 100.0f);
HistogramWindowChangedNotify.Broadcast(HistogramPreviewWindow);
InvalidateCanvas();
}
void SLogVisualizer::OnDrawLogEntriesPathChanged(ESlateCheckBoxState::Type NewState)
{
bDrawLogEntriesPath = (NewState == ESlateCheckBoxState::Checked);
InvalidateCanvas();
}
ESlateCheckBoxState::Type SLogVisualizer::GetDrawLogEntriesPathState() const
{
return bDrawLogEntriesPath ? ESlateCheckBoxState::Checked : ESlateCheckBoxState::Unchecked;
}
void SLogVisualizer::OnIgnoreTrivialLogs(ESlateCheckBoxState::Type NewState)
{
bIgnoreTrivialLogs = (NewState == ESlateCheckBoxState::Checked);
DoFullUpdate();
}
ESlateCheckBoxState::Type SLogVisualizer::GetIgnoreTrivialLogs() const
{
return bIgnoreTrivialLogs ? ESlateCheckBoxState::Checked : ESlateCheckBoxState::Unchecked;
}
void SLogVisualizer::OnChangeHistogramLabelLocation(ESlateCheckBoxState::Type NewState)
{
bShowHistogramLabelsOutside = (NewState == ESlateCheckBoxState::Checked);
InvalidateCanvas();
}
ESlateCheckBoxState::Type SLogVisualizer::GetHistogramLabelLocation() const
{
return bShowHistogramLabelsOutside ? ESlateCheckBoxState::Checked : ESlateCheckBoxState::Unchecked;
}
void SLogVisualizer::OnStickToLastData(ESlateCheckBoxState::Type NewState)
{
bStickToLastData = (NewState == ESlateCheckBoxState::Checked);
InvalidateCanvas();
}
ESlateCheckBoxState::Type SLogVisualizer::GetStickToLastData() const
{
return bStickToLastData ? ESlateCheckBoxState::Checked : ESlateCheckBoxState::Unchecked;
}
void SLogVisualizer::OnToggleCamera(ESlateCheckBoxState::Type NewState)
{
UWorld* World = GetWorld();
if (ALogVisualizerCameraController::IsEnabled(World))
{
ALogVisualizerCameraController::DisableCamera(World);
}
else
{
ALogVisualizerCameraController::EnableCamera(World);
}
InvalidateCanvas();
}
ESlateCheckBoxState::Type SLogVisualizer::GetToggleCameraState() const
{
return ALogVisualizerCameraController::IsEnabled(GetWorld())
? ESlateCheckBoxState::Checked : ESlateCheckBoxState::Unchecked;
}
void SLogVisualizer::OnOffsetDataSets(ESlateCheckBoxState::Type NewState)
{
bOffsetDataSet = (NewState == ESlateCheckBoxState::Checked);
InvalidateCanvas();
}
ESlateCheckBoxState::Type SLogVisualizer::GetOffsetDataSets() const
{
return bOffsetDataSet ? ESlateCheckBoxState::Checked : ESlateCheckBoxState::Unchecked;
}
void SLogVisualizer::OnHistogramGraphsFilter(ESlateCheckBoxState::Type NewState)
{
bHistogramGraphsFilter = (NewState == ESlateCheckBoxState::Checked);
QuickFilterText.Empty();
QuickFilterBox->SetText(FText::FromString(QuickFilterText));
LogsList.Reset();
OutEntriesCached.Reset();
RebuildFilteredList();
if (LogVisualizer && LogVisualizer->Logs.IsValidIndex(SelectedLogIndex))
{
TSharedPtr<FActorsVisLog> Log = LogVisualizer->Logs[SelectedLogIndex];
if (Log.IsValid() && Log->Entries.IsValidIndex(LogEntryIndex))
{
ShowEntry(Log->Entries[LogEntryIndex].Get());
}
}
}
ESlateCheckBoxState::Type SLogVisualizer::GetHistogramGraphsFilter() const
{
return bHistogramGraphsFilter ? ESlateCheckBoxState::Checked : ESlateCheckBoxState::Unchecked;
}
//----------------------------------------------------------------------//
// Drawing
//----------------------------------------------------------------------//
void SLogVisualizer::DrawOnCanvas(UCanvas* Canvas, APlayerController*)
{
UWorld* World = GetWorld();
if (World != NULL && LogVisualizer->Logs.IsValidIndex(SelectedLogIndex))
{
TSharedPtr<FActorsVisLog> Log = LogVisualizer->Logs[SelectedLogIndex];
const TArray<TSharedPtr<FVisLogEntry> >& Entries = Log->Entries;
if (bDrawLogEntriesPath)
{
const TSharedPtr<FVisLogEntry>* Entry = Entries.GetTypedData();
FVector Location = (*Entry)->Location;
++Entry;
for (int32 Index = 1; Index < Entries.Num(); ++Index, ++Entry)
{
const FVector CurrentLocation = (*Entry)->Location;
DrawDebugLine(World, Location, CurrentLocation, FColor(160, 160, 240));
Location = CurrentLocation;
}
}
if (Entries.IsValidIndex(LogEntryIndex))
{
// draw all additional data stored in current entry
const TSharedPtr<FVisLogEntry>& Entry = Entries[LogEntryIndex];
// mark current location
DrawDebugCone(World, Entry->Location, /*Direction*/FVector(0, 0, 1), /*Length*/200.f
, PI/64, PI/64, /*NumSides*/16, FColor::Red);
UFont* Font = GEngine->GetSmallFont();
FCanvasTextItem TextItem( FVector2D::ZeroVector, FText::GetEmpty(), Font, FLinearColor::White );
const FString TimeStampString = FString::Printf(TEXT("%.2f"), Entry->TimeStamp);
const FVector EntryScreenLoc = Canvas->Project(Entry->Location);
Canvas->SetDrawColor(FColor::Black);
Canvas->DrawText(Font, TimeStampString,EntryScreenLoc.X+1, EntryScreenLoc.Y+1);
Canvas->SetDrawColor(FColor::White);
Canvas->DrawText(Font, TimeStampString, EntryScreenLoc.X, EntryScreenLoc.Y);
//let's draw histogram data
struct FGraphLineData
{
FName DataName;
TArray<FVector2D> Samples;
};
typedef TMap<FName, FGraphLineData > FGraphLines;
struct FGraphData
{
FGraphData() : Min(FVector2D(FLT_MAX, FLT_MAX)), Max(FVector2D(FLT_MIN, FLT_MIN)) {}
FVector2D Min, Max;
TMap<FName, FGraphLineData> GraphLines;
};
TMap<FName, FGraphData> CollectedGraphs;
float MinTime, MaxTime;
Timeline->GetMinMaxValues(MinTime, MaxTime);
const float StartTime = Timeline->GetOffset() + MinTime;
const float EndTime = StartTime + (MaxTime - MinTime) / this->GetZoom();
const float WindowHalfWidth = (EndTime - StartTime) * HistogramPreviewWindow * 0.01 * 0.5;
const FVector2D TimeStampWindow(Entry->TimeStamp - WindowHalfWidth, Entry->TimeStamp + WindowHalfWidth);
int32 ColorIndex = 0;
for (int32 EntryIndex = 0; EntryIndex < Entries.Num(); ++EntryIndex)
{
const TSharedPtr<FVisLogEntry>& CurrentEntry = Entries[EntryIndex];
if (HistogramPreviewWindow <= 0)
{
if (CurrentEntry->TimeStamp > Entry->TimeStamp)
{
break;
}
}
else
{
if (CurrentEntry->TimeStamp < TimeStampWindow.X)
{
continue;
}
if (CurrentEntry->TimeStamp > TimeStampWindow.Y)
{
break;
}
}
const int32 SamplesNum = CurrentEntry->HistogramSamples.Num();
for (int32 SampleIndex = 0; SampleIndex < SamplesNum; ++SampleIndex)
{
FVisLogEntry::FHistogramSample CurrentSample = CurrentEntry->HistogramSamples[SampleIndex];
const FName CurrentCategory = CurrentSample.Category;
const FName CurrentGraphName = CurrentSample.GraphName;
const FName CurrentDataName = CurrentSample.DataName;
const bool bIsValidByFilter = FilterListPtr->IsFilterEnabled(CurrentSample.GraphName.ToString(), CurrentSample.DataName.ToString(), ELogVerbosity::All);
const bool bCurrentDataNamePassed = !bHistogramGraphsFilter || (QuickFilterText.Len() == 0 || CurrentDataName.ToString().Find(QuickFilterText) != INDEX_NONE);
if (!FilterListPtr.IsValid() || (bIsValidByFilter /*&& bCurrentCategoryPassed*/ && bCurrentDataNamePassed))
{
FGraphData &GraphData = CollectedGraphs.FindOrAdd(CurrentSample.GraphName);
FGraphLineData &LineData = GraphData.GraphLines.FindOrAdd(CurrentSample.DataName);
LineData.DataName = CurrentSample.DataName;
LineData.Samples.Add( CurrentSample.SampleValue );
GraphData.Min.X = FMath::Min(GraphData.Min.X, CurrentSample.SampleValue.X);
GraphData.Min.Y = FMath::Min(GraphData.Min.Y, CurrentSample.SampleValue.Y);
GraphData.Max.X = FMath::Max(GraphData.Max.X, CurrentSample.SampleValue.X);
GraphData.Max.Y = FMath::Max(GraphData.Max.Y, CurrentSample.SampleValue.Y);
}
}
}
const float GoldenRatioConjugate = 0.618033988749895f;
int32 GraphIndex = 0;
if (CollectedGraphs.Num() > 0)
{
const int NumberOfGraphs = CollectedGraphs.Num();
const int32 NumberOfColumns = FMath::CeilToInt(FMath::Sqrt(NumberOfGraphs));
int32 NumberOfRows = FMath::FloorToInt(NumberOfGraphs / NumberOfColumns);
if (NumberOfGraphs - NumberOfRows * NumberOfColumns > 0)
{
NumberOfRows += 1;
}
const int32 MaxNumberOfGraphs = FMath::Max(NumberOfRows, NumberOfColumns);
const float GraphWidth = 0.8f / NumberOfColumns;
const float GraphHeight = 0.8f / NumberOfRows;
const float XGraphSpacing = 0.2f / (MaxNumberOfGraphs + 1);
const float YGraphSpacing = 0.2f / (MaxNumberOfGraphs + 1);
const float StartX = XGraphSpacing;
float StartY = 0.5 + (0.5 * NumberOfRows - 1) * (GraphHeight + YGraphSpacing);
float CurrentX = StartX;
float CurrentY = StartY;
int32 GraphIndex = 0;
int32 CurrentColumn = 0;
int32 CurrentRow = 0;
for (auto It(CollectedGraphs.CreateIterator()); It; ++It)
{
TWeakObjectPtr<UReporterGraph> HistogramGraph = Canvas->GetReporterGraph();
if (!HistogramGraph.IsValid())
{
break;
}
HistogramGraph->SetNumGraphLines(It->Value.GraphLines.Num());
int32 LineIndex = 0;
UFont* Font = GEngine->GetSmallFont();
int32 MaxStringSize = 0;
float Hue = 0;// StartGoldenRatio[GraphIndex++];
auto& CategoriesForGraph = UsedGraphCategories.FindOrAdd(It->Key.ToString());
It->Value.GraphLines.KeySort(TLess<FName>());
for (auto LinesIt(It->Value.GraphLines.CreateConstIterator()); LinesIt; ++LinesIt)
{
const FString DataName = LinesIt->Value.DataName.ToString();
int32 CategoryIndex = CategoriesForGraph.Find(DataName);
if (CategoryIndex == INDEX_NONE)
{
CategoryIndex = CategoriesForGraph.AddUnique(DataName);
}
Hue = CategoryIndex * GoldenRatioConjugate;
if (Hue > 1)
{
Hue -= FMath::FloorToFloat(Hue);
}
HistogramGraph->GetGraphLine(LineIndex)->Color = FLinearColor::FGetHSV(Hue * 255, 0, 244);
HistogramGraph->GetGraphLine(LineIndex)->LineName = DataName;
HistogramGraph->GetGraphLine(LineIndex)->Data.Append(LinesIt->Value.Samples);
int32 DummyY, CurrentX;
StringSize(Font, CurrentX, DummyY, *LinesIt->Value.DataName.ToString());
MaxStringSize = CurrentX > MaxStringSize ? CurrentX : MaxStringSize;
++LineIndex;
}
FVector2D GraphSpaceSize;
GraphSpaceSize.Y = GraphSpaceSize.X = 0.8f / CollectedGraphs.Num();
HistogramGraph->SetGraphScreenSize(CurrentX, CurrentX + GraphWidth, CurrentY, CurrentY + GraphHeight);
CurrentX += GraphWidth + XGraphSpacing;
HistogramGraph->SetAxesMinMax(FVector2D(TimeStampWindow.X, It->Value.Min.Y), FVector2D(TimeStampWindow.Y, It->Value.Max.Y));
HistogramGraph->SetNumThresholds(0);
HistogramGraph->SetStyles(EGraphAxisStyle::Grid, EGraphDataStyle::Lines);
HistogramGraph->SetBackgroundColor( FColor(0,0,0, 200) );
HistogramGraph->SetLegendPosition(bShowHistogramLabelsOutside ? ELegendPosition::Outside : ELegendPosition::Inside);
HistogramGraph->OffsetDataSets(bOffsetDataSet);
HistogramGraph->bVisible = true;
HistogramGraph->Draw(Canvas);
++GraphIndex;
if (++CurrentColumn >= NumberOfColumns)
{
CurrentColumn = 0;
CurrentRow++;
CurrentX = StartX;
CurrentY -= GraphHeight + YGraphSpacing;
}
}
}
AActor* HelperActor = FLogVisualizerModule::Get()->GetHelperActor(World);
for (const auto CurrentData : Entry->DataBlocks)
{
const FName TagName = CurrentData.TagName;
const bool bIsValidByFilter = FilterListPtr->IsFilterEnabled(CurrentData.Category.ToString(), ELogVerbosity::All) && FilterListPtr->IsFilterEnabled(CurrentData.TagName.ToString(), ELogVerbosity::All);
FVisualLogExtensionInterface* Extension = FVisualLog::Get().GetExtensionForTag(TagName);
if (!Extension)
{
continue;
}
if (!bIsValidByFilter)
{
Extension->DisableDrawingForData(World, Canvas, HelperActor, TagName, CurrentData, Entry->TimeStamp);
}
else
{
Extension->DrawData(World, Canvas, HelperActor, TagName, CurrentData, Entry->TimeStamp);
}
}
const FVisLogEntry::FElementToDraw* ElementToDraw = Entry->ElementsToDraw.GetTypedData();
const int32 ElementsCount = Entry->ElementsToDraw.Num();
for (int32 ElementIndex = 0; ElementIndex < ElementsCount; ++ElementIndex, ++ElementToDraw)
{
Merging using UE4-Fortnite-To-UE4 up to CL 2082758 Includes following engine CLs: CL 2080462: Added verbosity selection to category filters in Log Visualizer window CL 2081939: Fixed crash in Log Visualizer and missing entry on timeline with log containing only 2 entries. CL 2082118: Fixes and improovements for VisLogs - fixed logs visualization for logs with only one entry (Log Visualizer window) - fixed logs spam about missing json field (Log Visualizer window) - fixed crash with categories in Log Visualization window - added category and verbosity serialization for vislog shape elements (vlog files) CL 2080253: Added categories to VisLog shapes CL 2081762: Fixes to Log Visualizer. Logs without any log lines but with geometry elements are set on timeline properly. CL 2081859: Added double click to Log Visualizer action, to move editor camera to view current log location CL 2080159: Gameply Tag Pin now only allows single select #TTP 335383 - Editor: GameplayTag Pin should only allow a single selection #proj UE4 #change Removes all other tags from the correct container when in single select mode, was a missed variable change from a previous TTP CL 2081306: Made changes to navigation filters that allow for usage of virtual verstion dtQueryFilter #UE4 The scary part here is that having a dtQueryFilter contan a vftable was messing up FRecastQueryFilter's vftable it was getting from INavigationQueryFilterInterface. Reversing order of parent clas declaration of FRecastQueryFilter fixed the issue, but it's scary and looks like a compiler issue. [CL 2088758 by Billy Bramer in Main branch]
2014-05-29 17:46:51 -04:00
if (FilterListPtr.IsValid() && !FilterListPtr->IsFilterEnabled(ElementToDraw->Category.ToString(), ElementToDraw->Verbosity))
{
continue;
}
const FColor Color = ElementToDraw->GetFColor();
Canvas->SetDrawColor(Color);
switch(ElementToDraw->GetType())
{
case FVisLogEntry::FElementToDraw::SinglePoint:
{
const float Radius = float(ElementToDraw->Radius);
const bool bDrawLabel = ElementToDraw->Description.IsEmpty() == false;
const FVector* Location = ElementToDraw->Points.GetTypedData();
for (int32 Index = 0; Index < ElementToDraw->Points.Num(); ++Index, ++Location)
{
DrawDebugSphere(World, *Location, Radius, 16, Color);
if (bDrawLabel)
{
const FVector ScreenLoc = Canvas->Project(*Location);
Canvas->DrawText(Font, FString::Printf(TEXT("%s_%d"), *ElementToDraw->Description, Index), ScreenLoc.X, ScreenLoc.Y);
}
}
}
break;
case FVisLogEntry::FElementToDraw::Segment:
{
const float Thickness = float(ElementToDraw->Thicknes);
const bool bDrawLabel = ElementToDraw->Description.IsEmpty() == false && ElementToDraw->Points.Num() > 2;
const FVector* Location = ElementToDraw->Points.GetTypedData();
for (int32 Index = 0; Index + 1 < ElementToDraw->Points.Num(); Index += 2, Location += 2)
{
DrawDebugLine(World, *Location, *(Location + 1), Color
, /*bPersistentLines*/false, /*LifeTime*/-1
, /*DepthPriority*/0, Thickness);
if (bDrawLabel)
{
const FString PrintString = FString::Printf(TEXT("%s_%d"), *ElementToDraw->Description, Index);
float TextXL, TextYL;
Canvas->StrLen(Font, PrintString, TextXL, TextYL);
const FVector ScreenLoc = Canvas->Project(*Location + (*(Location+1)-*Location)/2);
Canvas->DrawText(Font, *PrintString, ScreenLoc.X - TextXL/2.0f, ScreenLoc.Y - TextYL/2.0f);
}
}
if (ElementToDraw->Description.IsEmpty() == false)
{
float TextXL, TextYL;
Canvas->StrLen(Font, ElementToDraw->Description, TextXL, TextYL);
const FVector ScreenLoc = Canvas->Project(ElementToDraw->Points[0]
+ (ElementToDraw->Points[1] - ElementToDraw->Points[0])/2);
Canvas->DrawText(Font, *ElementToDraw->Description, ScreenLoc.X - TextXL/2.0f, ScreenLoc.Y - TextYL/2.0f);
}
}
break;
case FVisLogEntry::FElementToDraw::Path:
{
const float Thickness = float(ElementToDraw->Thicknes);
FVector Location = ElementToDraw->Points[0];
for (int32 Index = 1; Index < ElementToDraw->Points.Num(); ++Index)
{
const FVector CurrentLocation = ElementToDraw->Points[Index];
DrawDebugLine(World, Location, CurrentLocation, Color
, /*bPersistentLines*/false, /*LifeTime*/-1
, /*DepthPriority*/0, Thickness);
Location = CurrentLocation;
}
}
break;
case FVisLogEntry::FElementToDraw::Box:
{
const float Thickness = float(ElementToDraw->Thicknes);
const bool bDrawLabel = ElementToDraw->Description.IsEmpty() == false && ElementToDraw->Points.Num() > 2;
const FVector* BoxExtent = ElementToDraw->Points.GetTypedData();
for (int32 Index = 0; Index + 1 < ElementToDraw->Points.Num(); Index += 2, BoxExtent += 2)
{
FBox Box(*BoxExtent, *(BoxExtent + 1));
DrawDebugBox(World, Box.GetCenter(), Box.GetExtent(), Color
, /*bPersistentLines*/false, /*LifeTime*/-1
, /*DepthPriority*/0/*, Thickness*/);
if (bDrawLabel)
{
const FString PrintString = FString::Printf(TEXT("%s_%d"), *ElementToDraw->Description, Index);
float TextXL, TextYL;
Canvas->StrLen(Font, PrintString, TextXL, TextYL);
const FVector ScreenLoc = Canvas->Project(Box.GetCenter());
Canvas->DrawText(Font, *PrintString, ScreenLoc.X - TextXL/2.0f, ScreenLoc.Y - TextYL/2.0f);
}
}
if (ElementToDraw->Description.IsEmpty() == false)
{
float TextXL, TextYL;
Canvas->StrLen(Font, ElementToDraw->Description, TextXL, TextYL);
const FVector ScreenLoc = Canvas->Project(ElementToDraw->Points[0]
+ (ElementToDraw->Points[1] - ElementToDraw->Points[0])/2);
Canvas->DrawText(Font, *ElementToDraw->Description, ScreenLoc.X - TextXL/2.0f, ScreenLoc.Y - TextYL/2.0f);
}
}
break;
}
}
}
}
}
//////////////////////////////////////////////////////////////////////////
const FSlateBrush* SLogVisualizer::GetRecordButtonBrush() const
{
if(LogVisualizer->IsRecording())
{
// If recording, show stop button
return FEditorStyle::GetBrush("LogVisualizer.Stop");
}
else
{
// If stopped, show record button
return FEditorStyle::GetBrush("LogVisualizer.Record");
}
}
FString SLogVisualizer::GetStatusText() const
{
return TEXT("");
}
ESlateCheckBoxState::Type SLogVisualizer::GetPauseState() const
{
UWorld* World = GetWorld();
return (World != NULL && (World->bPlayersOnly || World->bPlayersOnlyPending)) ? ESlateCheckBoxState::Checked : ESlateCheckBoxState::Unchecked;
}
FReply SLogVisualizer::OnRecordButtonClicked()
{
// Toggle recording state
LogVisualizer->SetIsRecording(!LogVisualizer->IsRecording());
return FReply::Handled();
}
FReply SLogVisualizer::OnLoad()
{
TArray<FString> OpenFilenames;
IDesktopPlatform* DesktopPlatform = FDesktopPlatformModule::Get();
bool bOpened = false;
if ( DesktopPlatform )
{
void* ParentWindowWindowHandle = NULL;
IMainFrameModule& MainFrameModule = FModuleManager::LoadModuleChecked<IMainFrameModule>(TEXT("MainFrame"));
const TSharedPtr<SWindow>& MainFrameParentWindow = MainFrameModule.GetParentWindow();
if ( MainFrameParentWindow.IsValid() && MainFrameParentWindow->GetNativeWindow().IsValid() )
{
ParentWindowWindowHandle = MainFrameParentWindow->GetNativeWindow()->GetOSWindowHandle();
}
bOpened = DesktopPlatform->OpenFileDialog(
ParentWindowWindowHandle,
LOCTEXT("OpenProjectBrowseTitle", "Open Project").ToString(),
LastBrowsePath,
TEXT(""),
LogVisualizer::FileTypes,
EFileDialogFlags::None,
OpenFilenames
);
}
if ( bOpened )
{
if ( OpenFilenames.Num() > 0 )
{
LastBrowsePath = OpenFilenames[0];
LoadFiles(OpenFilenames);
}
}
DoFullUpdate();
return FReply::Handled();
}
FReply SLogVisualizer::OnSave()
{
// Prompt the user for the filenames
TArray<FString> SaveFilenames;
IDesktopPlatform* DesktopPlatform = FDesktopPlatformModule::Get();
bool bSaved = false;
if ( DesktopPlatform )
{
void* ParentWindowWindowHandle = NULL;
IMainFrameModule& MainFrameModule = FModuleManager::LoadModuleChecked<IMainFrameModule>(TEXT("MainFrame"));
const TSharedPtr<SWindow>& MainFrameParentWindow = MainFrameModule.GetParentWindow();
if ( MainFrameParentWindow.IsValid() && MainFrameParentWindow->GetNativeWindow().IsValid() )
{
ParentWindowWindowHandle = MainFrameParentWindow->GetNativeWindow()->GetOSWindowHandle();
}
bSaved = DesktopPlatform->SaveFileDialog(
ParentWindowWindowHandle,
LOCTEXT("NewProjectBrowseTitle", "Choose a project location").ToString(),
LastBrowsePath,
TEXT(""),
LogVisualizer::FileTypes,
EFileDialogFlags::None,
SaveFilenames
);
}
if ( bSaved )
{
if ( SaveFilenames.Num() > 0 )
{
LastBrowsePath = SaveFilenames[0];
SaveSelectedLogs(SaveFilenames[0]);
/*CurrentProjectFilePath = FPaths::GetPath(FPaths::GetPath(SaveFilenames[0]));
CurrentProjectFileName = FPaths::GetBaseFilename(SaveFilenames[0]);*/
}
}
return FReply::Handled();
}
FReply SLogVisualizer::OnRemove()
{
TArray< TSharedPtr<FLogsListItem> > ItemsToRemove = LogsListWidget->GetSelectedItems();
if (ItemsToRemove.Num() > 0)
{
TArray<int32> IndicesToRemove;
IndicesToRemove.AddUninitialized(ItemsToRemove.Num());
for (int32 ListItemIndex = 0; ListItemIndex < ItemsToRemove.Num(); ++ListItemIndex)
{
IndicesToRemove[ListItemIndex] = ItemsToRemove[ListItemIndex]->LogIndex;
}
IndicesToRemove.Sort();
int32 PrevIdx = -1;
for (int32 LogToRemove = IndicesToRemove.Num() - 1; LogToRemove >= 0; --LogToRemove)
{
if (IndicesToRemove[LogToRemove] == PrevIdx)
{
continue;
}
LogVisualizer->Logs.RemoveAtSwap(IndicesToRemove[LogToRemove], 1, false);
PrevIdx = IndicesToRemove[LogToRemove];
const int32 IndexInList = FindIndexInLogsList(IndicesToRemove[LogToRemove]);
if (IndexInList != INDEX_NONE)
{
LogsList.RemoveAtSwap(IndexInList);
}
}
LogsListWidget->ClearSelection();
LogsList.Reset();
OutEntriesCached.Reset();
RebuildFilteredList();
}
return FReply::Handled();
}
void SLogVisualizer::OnPauseChanged(ESlateCheckBoxState::Type NewState)
{
UWorld* World = GetWorld();
if (World != NULL)
{
if (NewState != ESlateCheckBoxState::Checked)
{
World->bPlayersOnly = false;
World->bPlayersOnlyPending = false;
ALogVisualizerCameraController::DisableCamera(World);
}
else
{
World->bPlayersOnlyPending = true;
// switch debug cam on
CameraController = ALogVisualizerCameraController::EnableCamera(World);
if (CameraController.IsValid())
{
CameraController->OnActorSelected = ALogVisualizerCameraController::FActorSelectedDelegate::CreateSP(
this, &SLogVisualizer::CameraActorSelected
);
CameraController->OnIterateLogEntries = ALogVisualizerCameraController::FLogEntryIterationDelegate::CreateSP(
this, &SLogVisualizer::IncrementCurrentLogIndex
);
}
}
}
}
void SLogVisualizer::CameraActorSelected(AActor* SelectedActor)
{
// find log corresponding to this Actor
if (SelectedActor == NULL || LogVisualizer == NULL)
{
return;
}
SelectActor(SelectedActor);
}
void SLogVisualizer::SelectActor(AActor* SelectedActor)
{
const AActor* LogOwner = FVisualLog::Get().GetVisualLogRedirection(SelectedActor);
const int32 LogIndex = LogVisualizer->GetLogIndexForActor(LogOwner);
if (LogVisualizer->Logs.IsValidIndex(LogIndex))
{
SelectedLogIndex = LogIndex;
// find item pointing to given log index
for (int32 ItemIndex = 0; ItemIndex < LogsList.Num(); ++ItemIndex)
{
if (LogsList[ItemIndex]->LogIndex == LogIndex)
{
TSharedPtr<FActorsVisLog> Log = LogVisualizer->Logs[SelectedLogIndex];
ShowLogEntry(LogsList[ItemIndex], Log->Entries[Log->Entries.Num()-1]);
break;
}
}
}
}
void SLogVisualizer::OnQuickFilterTextChanged(const FText& CommentText, ETextCommit::Type CommitInfo)
{
QuickFilterText = CommentText.ToString();
OnLogCategoryFiltersChanged();
}
void SLogVisualizer::FilterTextCommitted(const FText& CommentText, ETextCommit::Type CommitInfo)
{
UpdateFilterInfo();
DoFullUpdate();
}
FString SLogVisualizer::GetLogEntryStatusText() const
{
return TEXT("Pause game with Pause button\nand select log entry to start viewing\nlog's content");
}
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 SLogVisualizer::OnSortByChanged(const EColumnSortPriority::Type SortPriority, const FName& ColumnName, const EColumnSortMode::Type NewSortMode)
{
SortBy = ELogsSortMode::ByName;
if (ColumnName == NAME_StartTime)
{
SortBy = ELogsSortMode::ByStartTime;
}
else if (ColumnName == NAME_EndTime)
{
SortBy = ELogsSortMode::ByEndTime;
}
LogsList.Reset();
OutEntriesCached.Reset();
RebuildFilteredList();
}
EColumnSortMode::Type SLogVisualizer::GetLogsSortMode() const
{
return (SortBy == ELogsSortMode::ByName) ? EColumnSortMode::Ascending : EColumnSortMode::None;
}
void SLogVisualizer::LoadFiles(TArray<FString>& OpenFilenames)
{
for (int FilenameIndex = 0; FilenameIndex < OpenFilenames.Num(); ++FilenameIndex)
{
FArchive* FileAr = IFileManager::Get().CreateFileReader(*(OpenFilenames[FilenameIndex]));
if (FileAr != NULL)
{
TSharedPtr<FJsonObject> Object;
TSharedRef<TJsonReader<UCS2CHAR> > Reader = TJsonReader<UCS2CHAR>::Create(FileAr);
if (FJsonSerializer::Deserialize(Reader, Object))
{
Merging using UE4-Fortnite-To-UE4 up to CL 2082758 Includes following engine CLs: CL 2080462: Added verbosity selection to category filters in Log Visualizer window CL 2081939: Fixed crash in Log Visualizer and missing entry on timeline with log containing only 2 entries. CL 2082118: Fixes and improovements for VisLogs - fixed logs visualization for logs with only one entry (Log Visualizer window) - fixed logs spam about missing json field (Log Visualizer window) - fixed crash with categories in Log Visualization window - added category and verbosity serialization for vislog shape elements (vlog files) CL 2080253: Added categories to VisLog shapes CL 2081762: Fixes to Log Visualizer. Logs without any log lines but with geometry elements are set on timeline properly. CL 2081859: Added double click to Log Visualizer action, to move editor camera to view current log location CL 2080159: Gameply Tag Pin now only allows single select #TTP 335383 - Editor: GameplayTag Pin should only allow a single selection #proj UE4 #change Removes all other tags from the correct container when in single select mode, was a missed variable change from a previous TTP CL 2081306: Made changes to navigation filters that allow for usage of virtual verstion dtQueryFilter #UE4 The scary part here is that having a dtQueryFilter contan a vftable was messing up FRecastQueryFilter's vftable it was getting from INavigationQueryFilterInterface. Reversing order of parent clas declaration of FRecastQueryFilter fixed the issue, but it's scary and looks like a compiler issue. [CL 2088758 by Billy Bramer in Main branch]
2014-05-29 17:46:51 -04:00
TArray< TSharedPtr<FJsonValue> > JsonLogs = Object->GetArrayField(VisualLogJson::TAG_LOGS);
for (int32 LogIndex = 0; LogIndex < JsonLogs.Num(); ++LogIndex)
{
Merging using UE4-Fortnite-To-UE4 up to CL 2082758 Includes following engine CLs: CL 2080462: Added verbosity selection to category filters in Log Visualizer window CL 2081939: Fixed crash in Log Visualizer and missing entry on timeline with log containing only 2 entries. CL 2082118: Fixes and improovements for VisLogs - fixed logs visualization for logs with only one entry (Log Visualizer window) - fixed logs spam about missing json field (Log Visualizer window) - fixed crash with categories in Log Visualization window - added category and verbosity serialization for vislog shape elements (vlog files) CL 2080253: Added categories to VisLog shapes CL 2081762: Fixes to Log Visualizer. Logs without any log lines but with geometry elements are set on timeline properly. CL 2081859: Added double click to Log Visualizer action, to move editor camera to view current log location CL 2080159: Gameply Tag Pin now only allows single select #TTP 335383 - Editor: GameplayTag Pin should only allow a single selection #proj UE4 #change Removes all other tags from the correct container when in single select mode, was a missed variable change from a previous TTP CL 2081306: Made changes to navigation filters that allow for usage of virtual verstion dtQueryFilter #UE4 The scary part here is that having a dtQueryFilter contan a vftable was messing up FRecastQueryFilter's vftable it was getting from INavigationQueryFilterInterface. Reversing order of parent clas declaration of FRecastQueryFilter fixed the issue, but it's scary and looks like a compiler issue. [CL 2088758 by Billy Bramer in Main branch]
2014-05-29 17:46:51 -04:00
TSharedPtr<FJsonObject> JsonLogObject = JsonLogs[LogIndex]->AsObject();
if (JsonLogObject.IsValid() != false)
{
if (JsonLogObject->HasTypedField<EJson::String>(VisualLogJson::TAG_NAME))
{
TSharedPtr<FActorsVisLog> NewLog = MakeShareable(new FActorsVisLog(JsonLogs[LogIndex]));
LogVisualizer->AddLoadedLog(NewLog);
}
}
}
Merging using UE4-Fortnite-To-UE4 up to CL 2082758 Includes following engine CLs: CL 2080462: Added verbosity selection to category filters in Log Visualizer window CL 2081939: Fixed crash in Log Visualizer and missing entry on timeline with log containing only 2 entries. CL 2082118: Fixes and improovements for VisLogs - fixed logs visualization for logs with only one entry (Log Visualizer window) - fixed logs spam about missing json field (Log Visualizer window) - fixed crash with categories in Log Visualization window - added category and verbosity serialization for vislog shape elements (vlog files) CL 2080253: Added categories to VisLog shapes CL 2081762: Fixes to Log Visualizer. Logs without any log lines but with geometry elements are set on timeline properly. CL 2081859: Added double click to Log Visualizer action, to move editor camera to view current log location CL 2080159: Gameply Tag Pin now only allows single select #TTP 335383 - Editor: GameplayTag Pin should only allow a single selection #proj UE4 #change Removes all other tags from the correct container when in single select mode, was a missed variable change from a previous TTP CL 2081306: Made changes to navigation filters that allow for usage of virtual verstion dtQueryFilter #UE4 The scary part here is that having a dtQueryFilter contan a vftable was messing up FRecastQueryFilter's vftable it was getting from INavigationQueryFilterInterface. Reversing order of parent clas declaration of FRecastQueryFilter fixed the issue, but it's scary and looks like a compiler issue. [CL 2088758 by Billy Bramer in Main branch]
2014-05-29 17:46:51 -04:00
bIgnoreTrivialLogs = false;
}
FileAr->Close();
}
}
if (OpenFilenames.Num() > 0)
{
LogsList.Reset();
OutEntriesCached.Reset();
RebuildFilteredList();
}
}
void SLogVisualizer::SaveSelectedLogs(FString& Filename)
{
TSharedPtr<FJsonObject> Object = MakeShareable(new FJsonObject);
TArray< TSharedPtr<FJsonValue> > EntriesArray;
TArray< TSharedPtr<FLogsListItem> > ItemsToSave = LogsListWidget->GetSelectedItems();
if (ItemsToSave.Num() == 0)
{
// store all
ItemsToSave = LogsList;
}
EntriesArray.Reserve(ItemsToSave.Num());
TSharedPtr<FLogsListItem>* LogListItem = ItemsToSave.GetTypedData();
for (int32 ItemIndex = 0; ItemIndex < ItemsToSave.Num(); ++ItemIndex, ++LogListItem)
{
if (LogListItem->IsValid() && LogVisualizer->Logs.IsValidIndex((*LogListItem)->LogIndex))
{
TSharedPtr<FActorsVisLog> Log = LogVisualizer->Logs[(*LogListItem)->LogIndex];
EntriesArray.Add(Log->ToJson());
}
}
if (EntriesArray.Num() > 0)
{
Merging using UE4-Fortnite-To-UE4 up to CL 2082758 Includes following engine CLs: CL 2080462: Added verbosity selection to category filters in Log Visualizer window CL 2081939: Fixed crash in Log Visualizer and missing entry on timeline with log containing only 2 entries. CL 2082118: Fixes and improovements for VisLogs - fixed logs visualization for logs with only one entry (Log Visualizer window) - fixed logs spam about missing json field (Log Visualizer window) - fixed crash with categories in Log Visualization window - added category and verbosity serialization for vislog shape elements (vlog files) CL 2080253: Added categories to VisLog shapes CL 2081762: Fixes to Log Visualizer. Logs without any log lines but with geometry elements are set on timeline properly. CL 2081859: Added double click to Log Visualizer action, to move editor camera to view current log location CL 2080159: Gameply Tag Pin now only allows single select #TTP 335383 - Editor: GameplayTag Pin should only allow a single selection #proj UE4 #change Removes all other tags from the correct container when in single select mode, was a missed variable change from a previous TTP CL 2081306: Made changes to navigation filters that allow for usage of virtual verstion dtQueryFilter #UE4 The scary part here is that having a dtQueryFilter contan a vftable was messing up FRecastQueryFilter's vftable it was getting from INavigationQueryFilterInterface. Reversing order of parent clas declaration of FRecastQueryFilter fixed the issue, but it's scary and looks like a compiler issue. [CL 2088758 by Billy Bramer in Main branch]
2014-05-29 17:46:51 -04:00
Object->SetArrayField(VisualLogJson::TAG_LOGS, EntriesArray);
FArchive* FileAr = IFileManager::Get().CreateFileWriter(*Filename);
if (FileAr != NULL)
{
TSharedRef<TJsonWriter<UCS2CHAR> > Writer = TJsonWriter<UCS2CHAR>::Create(FileAr);
FJsonSerializer::Serialize( Object.ToSharedRef(), Writer );
FileAr->Close();
}
}
}
#undef LOCTEXT_NAMESPACE
#endif //ENABLE_VISUAL_LOG