You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
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]
408 lines
11 KiB
C++
408 lines
11 KiB
C++
// Copyright 1998-2014 Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "LogVisualizerPCH.h"
|
|
#include "SLogBar.h"
|
|
|
|
const float SLogBar::SubPixelMinSize = 3.0f;
|
|
const float SLogBar::TimeUnit = 1.f/60.f;
|
|
const float SLogBar::MaxUnitSizePx = 16.f;
|
|
|
|
FColor SLogBar::ColorPalette[] = {
|
|
FColor( 0xff00A480 ),
|
|
FColor( 0xff62E200 ),
|
|
FColor( 0xff8F04A8 ),
|
|
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 )
|
|
};
|
|
|
|
void SLogBar::Construct( const FArguments& InArgs )
|
|
{
|
|
OnSelectionChanged = InArgs._OnSelectionChanged;
|
|
OnGeometryChanged = InArgs._OnGeometryChanged;
|
|
ShouldDrawSelection = InArgs._ShouldDrawSelection;
|
|
DisplayedTime = InArgs._DisplayedTime;
|
|
CurrentEntryIndex = InArgs._CurrentEntryIndex;
|
|
|
|
BackgroundImage = FEditorStyle::GetBrush("LogVisualizer.LogBar.Background");
|
|
FillImage = FEditorStyle::GetBrush("LogVisualizer.LogBar.EntryDefault");
|
|
SelectedImage = FEditorStyle::GetBrush("LogVisualizer.LogBar.Selected");
|
|
TimeMarkImage = FEditorStyle::GetBrush("LogVisualizer.LogBar.TimeMark");
|
|
|
|
LastHoveredEvent = INDEX_NONE;
|
|
Zoom = 1.0f;
|
|
Offset = 0.0f;
|
|
StartTime = 0.0;
|
|
TotalTime = 1.0;
|
|
RowIndex = INDEX_NONE;
|
|
bShouldDrawSelection = false;
|
|
}
|
|
|
|
int32 SLogBar::OnPaint( const FGeometry& AllottedGeometry, const FSlateRect& MyClippingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled ) const
|
|
{
|
|
// Used to track the layer ID we will return.
|
|
int32 RetLayerId = LayerId;
|
|
|
|
bool bEnabled = ShouldBeEnabled( bParentEnabled );
|
|
const ESlateDrawEffect::Type DrawEffects = bEnabled ? ESlateDrawEffect::None : ESlateDrawEffect::DisabledEffect;
|
|
|
|
const FColor ColorAndOpacitySRGB = InWidgetStyle.GetColorAndOpacityTint();
|
|
static const FColor SelectedBarColor(255, 255, 255, 255);
|
|
static const FColor CurrentTimeColor(140, 255, 255, 255);
|
|
|
|
// Paint inside the border only.
|
|
const FVector2D BorderPadding = FEditorStyle::GetVector("ProgressBar.BorderPadding");
|
|
FPaintGeometry ForegroundPaintGeometry = AllottedGeometry.ToInflatedPaintGeometry( -BorderPadding );
|
|
const FSlateRect ForegroundClippingRect = ForegroundPaintGeometry.ToSlateRect().IntersectionWith( MyClippingRect );
|
|
|
|
const float LogBarWidth = AllottedGeometry.Size.X;
|
|
|
|
FSlateDrawElement::MakeBox(
|
|
OutDrawElements,
|
|
RetLayerId++,
|
|
AllottedGeometry.ToPaintGeometry(),
|
|
BackgroundImage,
|
|
MyClippingRect,
|
|
DrawEffects,
|
|
ColorAndOpacitySRGB
|
|
);
|
|
|
|
// Draw all bars
|
|
int32 EntryIndex = 0;
|
|
while (EntryIndex < Entries.Num())
|
|
{
|
|
float CurrentStartX, CurrentEndX;
|
|
TSharedPtr<FVisLogEntry> Entry = Entries[EntryIndex];
|
|
if (!Entry.IsValid() || !CalculateEntryGeometry(Entry.Get(), AllottedGeometry, CurrentStartX, CurrentEndX))
|
|
{
|
|
EntryIndex++;
|
|
continue;
|
|
}
|
|
|
|
// find bar width, connect all contiguous bars to draw them as one geometry (rendering optimization)
|
|
float BarWidth = 0;
|
|
int32 StartIndex = EntryIndex;
|
|
float LastEndX = MAX_FLT;
|
|
for (; StartIndex < Entries.Num(); ++StartIndex)
|
|
{
|
|
TSharedPtr<FVisLogEntry> Entry = Entries[StartIndex];
|
|
float StartX, EndX;
|
|
if (!Entry.IsValid() || !CalculateEntryGeometry(Entry.Get(), AllottedGeometry, StartX, EndX))
|
|
{
|
|
break;
|
|
}
|
|
if (StartX > LastEndX)
|
|
{
|
|
break;
|
|
}
|
|
BarWidth = EndX - CurrentStartX;
|
|
LastEndX = EndX;
|
|
}
|
|
|
|
if (BarWidth > 0)
|
|
{
|
|
// Draw Event bar
|
|
FSlateDrawElement::MakeBox(
|
|
OutDrawElements,
|
|
RetLayerId++,
|
|
AllottedGeometry.ToPaintGeometry(
|
|
FVector2D(CurrentStartX, 0.0f),
|
|
FVector2D(BarWidth, AllottedGeometry.Size.Y)),
|
|
FillImage,
|
|
ForegroundClippingRect,
|
|
DrawEffects,
|
|
ColorPalette[0]
|
|
);
|
|
}
|
|
|
|
EntryIndex = StartIndex;
|
|
}
|
|
|
|
// draw "current time"
|
|
{
|
|
const float RelativePos = Offset + (DisplayedTime.Execute() - StartTime) / TotalTime * Zoom;
|
|
const float PosX = (float)(LogBarWidth * RelativePos);
|
|
const float ClampedSize = FMath::Clamp(TimeUnit / TotalTime * Zoom, 0.0f, 1.0f );
|
|
float CurrentTimeMarkWidth = (float)FMath::Max(LogBarWidth * ClampedSize
|
|
, ClampedSize > 0.0f ? SubPixelMinSize : 0.0f);
|
|
|
|
// Draw Event bar
|
|
FSlateDrawElement::MakeBox(
|
|
OutDrawElements,
|
|
RetLayerId++,
|
|
AllottedGeometry.ToPaintGeometry(
|
|
FVector2D( PosX - 2.f, 0.0f ),
|
|
FVector2D( CurrentTimeMarkWidth + 4.f, AllottedGeometry.Size.Y )),
|
|
TimeMarkImage,
|
|
ForegroundClippingRect,
|
|
DrawEffects,
|
|
CurrentTimeColor
|
|
);
|
|
}
|
|
|
|
if (bShouldDrawSelection)
|
|
{
|
|
int32 EntryIndex = CurrentEntryIndex.IsBound() ? CurrentEntryIndex.Execute() : INDEX_NONE;
|
|
if (Entries.IsValidIndex(EntryIndex) == true)
|
|
{
|
|
TSharedPtr<FVisLogEntry> Entry = Entries[EntryIndex];
|
|
float StartX, EndX;
|
|
if (CalculateEntryGeometry( Entry.Get(), AllottedGeometry, StartX, EndX ) )
|
|
{
|
|
// Draw Event bar
|
|
FSlateDrawElement::MakeBox(
|
|
OutDrawElements,
|
|
RetLayerId++,
|
|
AllottedGeometry.ToPaintGeometry(
|
|
FVector2D( StartX, 0.0f ),
|
|
FVector2D( EndX - StartX, AllottedGeometry.Size.Y )),
|
|
SelectedImage,
|
|
ForegroundClippingRect,
|
|
DrawEffects,
|
|
SelectedBarColor
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
return RetLayerId - 1;
|
|
}
|
|
|
|
void SLogBar::Tick( const FGeometry& AllottedGeometry, const double InCurrentTime, const float InDeltaTime )
|
|
{
|
|
if( OnGeometryChanged.IsBound() )
|
|
{
|
|
if( AllottedGeometry != this->LastGeometry )
|
|
{
|
|
OnGeometryChanged.ExecuteIfBound(AllottedGeometry);
|
|
LastGeometry = AllottedGeometry;
|
|
}
|
|
}
|
|
|
|
bShouldDrawSelection = ShouldDrawSelection.IsBound() && ShouldDrawSelection.Execute() == true;
|
|
|
|
SLeafWidget::Tick( AllottedGeometry, InCurrentTime, InDeltaTime );
|
|
}
|
|
|
|
void SLogBar::SelectEntry(const FGeometry& MyGeometry, const float ClickX)
|
|
{
|
|
int32 BestDistance = 0x7fffffff;
|
|
int32 LastDistance = 0x7fffffff;
|
|
|
|
// Go through all events and check if at least one has been clicked
|
|
int32 BestIndex = INDEX_NONE;
|
|
int32 EntryIndex = INDEX_NONE;
|
|
if (Entries.Num() == 1)
|
|
{
|
|
BestIndex = 0;
|
|
}
|
|
else
|
|
{
|
|
for (EntryIndex = 0; EntryIndex < Entries.Num(); ++EntryIndex)
|
|
{
|
|
TSharedPtr<FVisLogEntry> Entry = Entries[EntryIndex];
|
|
float StartX, EndX;
|
|
if (CalculateEntryGeometry(Entry.Get(), MyGeometry, StartX, EndX))
|
|
{
|
|
const int32 Distance = FMath::Abs(ClickX - StartX);
|
|
if (Distance < BestDistance)
|
|
{
|
|
BestDistance = Distance;
|
|
BestIndex = EntryIndex;
|
|
}
|
|
else if (Distance > LastDistance)
|
|
{
|
|
break;
|
|
}
|
|
LastDistance = Distance;
|
|
}
|
|
}
|
|
}
|
|
SelectEntryAtIndex(BestIndex);
|
|
}
|
|
|
|
int32 SLogBar::GetEntryIndexAtTime(float Time) const
|
|
{
|
|
int BestIndex = INDEX_NONE;
|
|
float BestTimeDiff = MAX_FLT;
|
|
float LastTimeDiff = MAX_FLT;
|
|
|
|
// Go through all events and check if at least one has been clicked
|
|
int32 EntryIndex = INDEX_NONE;
|
|
for( EntryIndex = 0; EntryIndex < Entries.Num(); ++EntryIndex )
|
|
{
|
|
TSharedPtr<FVisLogEntry> Entry = Entries[EntryIndex];
|
|
const float TimeDiff = FMath::Abs(Entry->TimeStamp - Time);
|
|
|
|
if (TimeDiff < BestTimeDiff)
|
|
{
|
|
BestTimeDiff = TimeDiff;
|
|
BestIndex = EntryIndex;
|
|
}
|
|
else if (TimeDiff > LastTimeDiff)
|
|
{
|
|
break;
|
|
}
|
|
LastTimeDiff = TimeDiff;
|
|
}
|
|
|
|
return BestIndex;
|
|
}
|
|
|
|
void SLogBar::SelectEntryAtIndex(const int32 Index)
|
|
{
|
|
if (Entries.IsValidIndex(Index) == false)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Execute OnSelectionChanged delegate
|
|
if( OnSelectionChanged.IsBound() )
|
|
{
|
|
OnSelectionChanged.ExecuteIfBound(Entries[Index]);
|
|
}
|
|
}
|
|
|
|
FReply SLogBar::OnMouseButtonDown( const FGeometry& MyGeometry, const FPointerEvent& MouseEvent )
|
|
{
|
|
if (MouseEvent.GetEffectingButton() == EKeys::LeftMouseButton)
|
|
{
|
|
// Translate click position from absolute to graph space
|
|
const float ClickX = MyGeometry.AbsoluteToLocal( MouseEvent.GetScreenSpacePosition() ).X;//( MyGeometry.AbsoluteToLocal( MouseEvent.GetScreenSpacePosition() ).X / MyGeometry.Size.X ) / Zoom - Offset / Zoom;
|
|
SelectEntry(MyGeometry, ClickX);
|
|
|
|
return FReply::Handled();
|
|
}
|
|
else
|
|
{
|
|
return FReply::Unhandled();
|
|
}
|
|
}
|
|
|
|
FReply SLogBar::OnMouseButtonUp( const FGeometry& MyGeometry, const FPointerEvent& MouseEvent )
|
|
{
|
|
// same behavior as when OnMouseButtonDown
|
|
return OnMouseButtonDown(MyGeometry, MouseEvent);
|
|
}
|
|
|
|
|
|
/**
|
|
* The system calls this method to notify the widget that a mouse moved within it. This event is bubbled.
|
|
*
|
|
* @param MyGeometry The Geometry of the widget receiving the event
|
|
* @param MouseEvent Information about the input event
|
|
*
|
|
* @return Whether the event was handled along with possible requests for the system to take action.
|
|
*/
|
|
FReply SLogBar::OnMouseMove( const FGeometry& MyGeometry, const FPointerEvent& MouseEvent )
|
|
{
|
|
const float HoverX = ( MyGeometry.AbsoluteToLocal( MouseEvent.GetScreenSpacePosition() ).X / MyGeometry.Size.X ) / Zoom - Offset / Zoom;
|
|
|
|
int32 HoveredEventIndex = INDEX_NONE;
|
|
|
|
for( int32 EntryIndex = 0; EntryIndex < Entries.Num(); EntryIndex++ )
|
|
{
|
|
TSharedPtr<FVisLogEntry> Entry = Entries[EntryIndex];
|
|
|
|
if( HoverX >= Entry->TimeStamp && Entry->TimeStamp <= HoverX + 1)
|
|
{
|
|
HoveredEventIndex = EntryIndex;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if( HoveredEventIndex != LastHoveredEvent )
|
|
{
|
|
/*if( HoveredEventIndex != INDEX_NONE )
|
|
{
|
|
this->SetToolTipText( Entries[ HoveredEventIndex ]->EventName );
|
|
}
|
|
else
|
|
{
|
|
this->SetToolTipText( TEXT( "" ) );
|
|
}*/
|
|
LastHoveredEvent = HoveredEventIndex;
|
|
}
|
|
|
|
if (MouseEvent.IsMouseButtonDown(EKeys::LeftMouseButton))
|
|
{
|
|
SelectEntry(MyGeometry, MyGeometry.AbsoluteToLocal( MouseEvent.GetScreenSpacePosition() ).X);
|
|
}
|
|
|
|
return SLeafWidget::OnMouseMove( MyGeometry, MouseEvent );
|
|
}
|
|
|
|
FVector2D SLogBar::ComputeDesiredSize() const
|
|
{
|
|
return FVector2D( 500.0f, 24.0f );
|
|
}
|
|
|
|
void SLogBar::SetEntries(const TArray<TSharedPtr<FVisLogEntry> >& InEntries, float InStartTime, float InTotalTime)
|
|
{
|
|
Entries = InEntries;
|
|
StartTime = InStartTime;
|
|
TotalTime = InTotalTime;
|
|
}
|
|
|
|
void SLogBar::OnCurrentTimeChanged(float NewTime)
|
|
{
|
|
const bool bUpdateSelection = ShouldDrawSelection.IsBound()
|
|
&& ShouldDrawSelection.Execute() == true ;
|
|
|
|
if (bUpdateSelection)
|
|
{
|
|
// find entry closest to desired time
|
|
FSimpleDelegateGraphTask::CreateAndDispatchWhenReady(
|
|
FSimpleDelegateGraphTask::FDelegate::CreateSP(this, &SLogBar::SelectEntryAtIndex, GetEntryIndexAtTime(NewTime))
|
|
, TEXT("Updating Log Entry shown in LogVisualizer")
|
|
, NULL
|
|
, ENamedThreads::GameThread
|
|
);
|
|
}
|
|
}
|
|
|
|
void SLogBar::SetZoomAndOffset(float InZoom, float InOffset)
|
|
{
|
|
SetZoom(InZoom);
|
|
SetOffset(InOffset);
|
|
}
|
|
|
|
void SLogBar::UpdateShouldDrawSelection()
|
|
{
|
|
/*const bool bNewShouldDraw = ShouldDrawSelection.Execute();
|
|
if (bNewShouldDraw != !!bShouldDrawSelection)
|
|
{
|
|
bShouldDrawSelection = bNewShouldDraw;
|
|
if (bNewShouldDraw)
|
|
{
|
|
check(DisplayedTime.IsBound());
|
|
SelectEntryAtIndex(GetEntryIndexAtTime(DisplayedTime.Execute()));
|
|
}
|
|
}*/
|
|
}
|
|
|