526 lines
18 KiB
C++
526 lines
18 KiB
C++
|
|
// Copyright Epic Games, Inc. All Rights Reserved.
|
||
|
|
|
||
|
|
#include "MarkersTimingTrack.h"
|
||
|
|
|
||
|
|
#include "Fonts/FontMeasure.h"
|
||
|
|
#include "Framework/Application/SlateApplication.h"
|
||
|
|
#include "Framework/MultiBox/MultiBoxBuilder.h"
|
||
|
|
#include "Styling/CoreStyle.h"
|
||
|
|
#include "TraceServices/AnalysisService.h"
|
||
|
|
|
||
|
|
// Insights
|
||
|
|
#include "Insights/Common/PaintUtils.h"
|
||
|
|
#include "Insights/InsightsManager.h"
|
||
|
|
#include "Insights/InsightsStyle.h"
|
||
|
|
#include "Insights/TimingProfilerManager.h"
|
||
|
|
#include "Insights/ViewModels/TimingTrackViewport.h"
|
||
|
|
|
||
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
|
|
||
|
|
#define LOCTEXT_NAMESPACE "MarkersTimingTrack"
|
||
|
|
|
||
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
|
|
||
|
|
INSIGHTS_IMPLEMENT_RTTI(FMarkersTimingTrack)
|
||
|
|
|
||
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
|
|
||
|
|
FMarkersTimingTrack::FMarkersTimingTrack()
|
||
|
|
: FBaseTimingTrack(TEXT("Markers (Bookmarks / Logs)"))
|
||
|
|
//, TimeMarkerBoxes()
|
||
|
|
//, TimeMarkerTexts()
|
||
|
|
,
|
||
|
|
bUseOnlyBookmarks(true),
|
||
|
|
Header(*this),
|
||
|
|
NumLogMessages(0),
|
||
|
|
NumDrawBoxes(0),
|
||
|
|
NumDrawTexts(0),
|
||
|
|
WhiteBrush(FInsightsStyle::Get().GetBrush("WhiteBrush")),
|
||
|
|
Font(FCoreStyle::GetDefaultFontStyle("Regular", 8))
|
||
|
|
{
|
||
|
|
SetValidLocations(ETimingTrackLocation::TopDocked | ETimingTrackLocation::BottomDocked);
|
||
|
|
SetOrder(FTimingTrackOrder::Markers);
|
||
|
|
}
|
||
|
|
|
||
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
|
|
||
|
|
FMarkersTimingTrack::~FMarkersTimingTrack()
|
||
|
|
{
|
||
|
|
}
|
||
|
|
|
||
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
|
|
||
|
|
void FMarkersTimingTrack::Reset()
|
||
|
|
{
|
||
|
|
FBaseTimingTrack::Reset();
|
||
|
|
|
||
|
|
TimeMarkerBoxes.Reset();
|
||
|
|
TimeMarkerTexts.Reset();
|
||
|
|
|
||
|
|
bUseOnlyBookmarks = true;
|
||
|
|
|
||
|
|
Header.Reset();
|
||
|
|
Header.SetIsInBackground(true);
|
||
|
|
Header.SetCanBeCollapsed(true);
|
||
|
|
|
||
|
|
NumLogMessages = 0;
|
||
|
|
NumDrawBoxes = 0;
|
||
|
|
NumDrawTexts = 0;
|
||
|
|
|
||
|
|
UpdateTrackNameAndHeight();
|
||
|
|
}
|
||
|
|
|
||
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
|
|
||
|
|
void FMarkersTimingTrack::UpdateTrackNameAndHeight()
|
||
|
|
{
|
||
|
|
if (bUseOnlyBookmarks)
|
||
|
|
{
|
||
|
|
const FString NameString = TEXT("Bookmarks");
|
||
|
|
SetName(NameString);
|
||
|
|
SetHeight(14.0f);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
const FString NameString = TEXT("Logs");
|
||
|
|
SetName(NameString);
|
||
|
|
SetHeight(28.0f);
|
||
|
|
}
|
||
|
|
|
||
|
|
Header.UpdateSize();
|
||
|
|
}
|
||
|
|
|
||
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
|
|
||
|
|
void FMarkersTimingTrack::Update(const ITimingTrackUpdateContext& Context)
|
||
|
|
{
|
||
|
|
Header.Update(Context);
|
||
|
|
|
||
|
|
const FTimingTrackViewport& Viewport = Context.GetViewport();
|
||
|
|
if (IsDirty() || Viewport.IsHorizontalViewportDirty())
|
||
|
|
{
|
||
|
|
ClearDirtyFlag();
|
||
|
|
|
||
|
|
UpdateDrawState(Viewport);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
|
|
||
|
|
void FMarkersTimingTrack::PostUpdate(const ITimingTrackUpdateContext& Context)
|
||
|
|
{
|
||
|
|
const float MouseY = Context.GetMousePosition().Y;
|
||
|
|
SetHoveredState(MouseY >= GetPosY() && MouseY < GetPosY() + GetHeight());
|
||
|
|
|
||
|
|
Header.PostUpdate(Context);
|
||
|
|
}
|
||
|
|
|
||
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
|
|
||
|
|
void FMarkersTimingTrack::UpdateDrawState(const FTimingTrackViewport& InViewport)
|
||
|
|
{
|
||
|
|
FTimeMarkerTrackBuilder Builder(*this, InViewport);
|
||
|
|
|
||
|
|
TSharedPtr<const Trace::IAnalysisSession> Session = FInsightsManager::Get()->GetSession();
|
||
|
|
if (Session.IsValid())
|
||
|
|
{
|
||
|
|
Trace::FAnalysisSessionReadScope SessionReadScope(*Session.Get());
|
||
|
|
|
||
|
|
const Trace::ILogProvider& LogProvider = Trace::ReadLogProvider(*Session.Get());
|
||
|
|
Builder.BeginLog(LogProvider);
|
||
|
|
|
||
|
|
LogProvider.EnumerateMessages(
|
||
|
|
Builder.GetViewport().GetStartTime(),
|
||
|
|
Builder.GetViewport().GetEndTime(),
|
||
|
|
[&Builder](const Trace::FLogMessage& Message)
|
||
|
|
{
|
||
|
|
Builder.AddLogMessage(Message);
|
||
|
|
});
|
||
|
|
|
||
|
|
Builder.EndLog();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
|
|
||
|
|
void FMarkersTimingTrack::Draw(const ITimingTrackDrawContext& Context) const
|
||
|
|
{
|
||
|
|
FDrawContext& DrawContext = Context.GetDrawContext();
|
||
|
|
const FTimingTrackViewport& Viewport = Context.GetViewport();
|
||
|
|
|
||
|
|
// Draw background.
|
||
|
|
const FLinearColor BackgroundColor(0.04f, 0.04f, 0.04f, 1.0f);
|
||
|
|
DrawContext.DrawBox(0.0f, GetPosY(), Viewport.GetWidth(), GetHeight(), WhiteBrush, BackgroundColor);
|
||
|
|
DrawContext.LayerId++;
|
||
|
|
|
||
|
|
Header.Draw(Context);
|
||
|
|
}
|
||
|
|
|
||
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
|
|
||
|
|
void FMarkersTimingTrack::PostDraw(const ITimingTrackDrawContext& Context) const
|
||
|
|
{
|
||
|
|
FDrawContext& DrawContext = Context.GetDrawContext();
|
||
|
|
const FTimingTrackViewport& Viewport = Context.GetViewport();
|
||
|
|
|
||
|
|
//////////////////////////////////////////////////
|
||
|
|
// Draw vertical lines.
|
||
|
|
// Multiple adjacent vertical lines with same color are merged into a single box.
|
||
|
|
|
||
|
|
float BoxY, BoxH;
|
||
|
|
if (IsCollapsed())
|
||
|
|
{
|
||
|
|
BoxY = GetPosY();
|
||
|
|
BoxH = GetHeight();
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
BoxY = 0.0f;
|
||
|
|
BoxH = Viewport.GetHeight();
|
||
|
|
}
|
||
|
|
|
||
|
|
const int32 NumBoxes = TimeMarkerBoxes.Num();
|
||
|
|
for (int32 BoxIndex = 0; BoxIndex < NumBoxes; BoxIndex++)
|
||
|
|
{
|
||
|
|
const FTimeMarkerBoxInfo& Box = TimeMarkerBoxes[BoxIndex];
|
||
|
|
DrawContext.DrawBox(Box.X, BoxY, Box.W, BoxH, WhiteBrush, Box.Color);
|
||
|
|
}
|
||
|
|
DrawContext.LayerId++;
|
||
|
|
NumDrawBoxes = NumBoxes;
|
||
|
|
|
||
|
|
//////////////////////////////////////////////////
|
||
|
|
// Draw texts (strings are already truncated).
|
||
|
|
|
||
|
|
const float CategoryY = GetPosY() + 2.0f;
|
||
|
|
const float MessageY = GetPosY() + (IsBookmarksTrack() ? 1.0f : 14.0f);
|
||
|
|
|
||
|
|
const int32 NumTexts = TimeMarkerTexts.Num();
|
||
|
|
for (int32 TextIndex = 0; TextIndex < NumTexts; TextIndex++)
|
||
|
|
{
|
||
|
|
const FTimeMarkerTextInfo& TextInfo = TimeMarkerTexts[TextIndex];
|
||
|
|
|
||
|
|
if (!IsBookmarksTrack() && TextInfo.Category.Len() > 0)
|
||
|
|
{
|
||
|
|
DrawContext.DrawText(TextInfo.X, CategoryY, TextInfo.Category, Font, TextInfo.Color);
|
||
|
|
NumDrawTexts++;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (TextInfo.Message.Len() > 0)
|
||
|
|
{
|
||
|
|
DrawContext.DrawText(TextInfo.X, MessageY, TextInfo.Message, Font, TextInfo.Color);
|
||
|
|
NumDrawTexts++;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
DrawContext.LayerId++;
|
||
|
|
|
||
|
|
//////////////////////////////////////////////////
|
||
|
|
|
||
|
|
Header.PostDraw(Context);
|
||
|
|
}
|
||
|
|
|
||
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
|
|
||
|
|
FReply FMarkersTimingTrack::OnMouseButtonDown(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent)
|
||
|
|
{
|
||
|
|
FReply Reply = FReply::Unhandled();
|
||
|
|
|
||
|
|
if (MouseEvent.GetEffectingButton() == EKeys::LeftMouseButton)
|
||
|
|
{
|
||
|
|
if (IsVisible() && IsHeaderHovered())
|
||
|
|
{
|
||
|
|
ToggleCollapsed();
|
||
|
|
Reply = FReply::Handled();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return Reply;
|
||
|
|
}
|
||
|
|
|
||
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
|
|
||
|
|
FReply FMarkersTimingTrack::OnMouseButtonDoubleClick(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent)
|
||
|
|
{
|
||
|
|
return OnMouseButtonDown(MyGeometry, MouseEvent);
|
||
|
|
}
|
||
|
|
|
||
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
|
|
||
|
|
void FMarkersTimingTrack::BuildContextMenu(FMenuBuilder& MenuBuilder)
|
||
|
|
{
|
||
|
|
MenuBuilder.BeginSection(TEXT("Misc"));
|
||
|
|
{
|
||
|
|
MenuBuilder.AddMenuEntry(
|
||
|
|
LOCTEXT("ContextMenu_ToggleCollapsed", "Collapsed"),
|
||
|
|
LOCTEXT("ContextMenu_ToggleCollapsed_Desc", "Whether the vertical marker lines are collapsed or expanded."),
|
||
|
|
FSlateIcon(),
|
||
|
|
FUIAction(FExecuteAction::CreateSP(this, &FMarkersTimingTrack::ToggleCollapsed),
|
||
|
|
FCanExecuteAction(),
|
||
|
|
FIsActionChecked::CreateSP(this, &FMarkersTimingTrack::IsCollapsed)),
|
||
|
|
NAME_None,
|
||
|
|
EUserInterfaceActionType::ToggleButton);
|
||
|
|
|
||
|
|
MenuBuilder.AddMenuEntry(
|
||
|
|
LOCTEXT("ContextMenu_Bookmarks", "Bookmarks"),
|
||
|
|
LOCTEXT("ContextMenu_Bookmarks_Desc", "Change this track to show only the bookmarks."),
|
||
|
|
FSlateIcon(),
|
||
|
|
FUIAction(FExecuteAction::CreateSP(this, &FMarkersTimingTrack::SetBookmarksTrack),
|
||
|
|
FCanExecuteAction(),
|
||
|
|
FIsActionChecked::CreateSP(this, &FMarkersTimingTrack::IsBookmarksTrack)),
|
||
|
|
NAME_None,
|
||
|
|
EUserInterfaceActionType::RadioButton);
|
||
|
|
|
||
|
|
MenuBuilder.AddMenuEntry(
|
||
|
|
LOCTEXT("ContextMenu_Logs", "Logs"),
|
||
|
|
LOCTEXT("ContextMenu_Logs_Desc", "Change this track to show all logs."),
|
||
|
|
FSlateIcon(),
|
||
|
|
FUIAction(FExecuteAction::CreateSP(this, &FMarkersTimingTrack::SetLogsTrack),
|
||
|
|
FCanExecuteAction(),
|
||
|
|
FIsActionChecked::CreateSP(this, &FMarkersTimingTrack::IsLogsTrack)),
|
||
|
|
NAME_None,
|
||
|
|
EUserInterfaceActionType::RadioButton);
|
||
|
|
}
|
||
|
|
MenuBuilder.EndSection();
|
||
|
|
}
|
||
|
|
|
||
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
|
// FTimeMarkerTrackBuilder
|
||
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
|
|
||
|
|
FTimeMarkerTrackBuilder::FTimeMarkerTrackBuilder(FMarkersTimingTrack& InTrack, const FTimingTrackViewport& InViewport)
|
||
|
|
: Track(InTrack), Viewport(InViewport), FontMeasureService(FSlateApplication::Get().GetRenderer()->GetFontMeasureService()), Font(FCoreStyle::GetDefaultFontStyle("Regular", 8))
|
||
|
|
{
|
||
|
|
Track.ResetCache();
|
||
|
|
Track.NumLogMessages = 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
|
|
||
|
|
void FTimeMarkerTrackBuilder::BeginLog(const Trace::ILogProvider& LogProvider)
|
||
|
|
{
|
||
|
|
LogProviderPtr = &LogProvider;
|
||
|
|
|
||
|
|
LastX1 = -1000.0f;
|
||
|
|
LastX2 = -1000.0f;
|
||
|
|
LastLogIndex = 0;
|
||
|
|
LastVerbosity = ELogVerbosity::NoLogging;
|
||
|
|
LastCategory = nullptr;
|
||
|
|
LastMessage = nullptr;
|
||
|
|
}
|
||
|
|
|
||
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
|
|
||
|
|
void FTimeMarkerTrackBuilder::AddLogMessage(const Trace::FLogMessage& Message)
|
||
|
|
{
|
||
|
|
Track.NumLogMessages++;
|
||
|
|
|
||
|
|
// Add also the log message imediately on the left of the screen (if any).
|
||
|
|
if (Track.NumLogMessages == 1 && Message.Index > 0)
|
||
|
|
{
|
||
|
|
// Note: Reading message at Index-1 will not work as expected when using filter!
|
||
|
|
// TODO: Search API like: LogProviderPtr->SearchMessage(StartIndex, ESearchDirection::Backward, LambdaPredicate, bResolveFormatString);
|
||
|
|
LogProviderPtr->ReadMessage(
|
||
|
|
Message.Index - 1,
|
||
|
|
[this](const Trace::FLogMessage& Message)
|
||
|
|
{
|
||
|
|
AddLogMessage(Message);
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
check(Message.Category != nullptr);
|
||
|
|
// check(Message.Category->Name != nullptr);
|
||
|
|
|
||
|
|
const TCHAR* CategoryName = Message.Category->Name != nullptr ? Message.Category->Name : TEXT("");
|
||
|
|
|
||
|
|
if (!Track.bUseOnlyBookmarks || FCString::Strcmp(CategoryName, TEXT("LogBookmark")) == 0)
|
||
|
|
{
|
||
|
|
float X = Viewport.TimeToSlateUnitsRounded(Message.Time);
|
||
|
|
if (X < 0.0f)
|
||
|
|
{
|
||
|
|
X = -1.0f;
|
||
|
|
}
|
||
|
|
AddTimeMarker(X, Message.Index, Message.Verbosity, CategoryName, Message.Message);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
|
|
||
|
|
FLinearColor FTimeMarkerTrackBuilder::GetColorByCategory(const TCHAR* const Category)
|
||
|
|
{
|
||
|
|
// Strip the "Log" prefix.
|
||
|
|
FString CategoryStr(Category);
|
||
|
|
if (CategoryStr.StartsWith(TEXT("Log")))
|
||
|
|
{
|
||
|
|
CategoryStr.RightChopInline(3, false);
|
||
|
|
}
|
||
|
|
|
||
|
|
uint32 Hash = 0;
|
||
|
|
for (const TCHAR* c = *CategoryStr; *c; ++c)
|
||
|
|
{
|
||
|
|
Hash = (Hash + *c) * 0x2c2c57ed;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Divided by 128.0 in order to force bright colors.
|
||
|
|
return FLinearColor(((Hash >> 16) & 0xFF) / 128.0f, ((Hash >> 8) & 0xFF) / 128.0f, (Hash & 0xFF) / 128.0f, 1.0f);
|
||
|
|
}
|
||
|
|
|
||
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
|
|
||
|
|
FLinearColor FTimeMarkerTrackBuilder::GetColorByVerbosity(const ELogVerbosity::Type Verbosity)
|
||
|
|
{
|
||
|
|
static FLinearColor Colors[] =
|
||
|
|
{
|
||
|
|
FLinearColor(0.0f, 0.0f, 0.0f, 1.0f), // NoLogging
|
||
|
|
FLinearColor(1.0f, 0.0f, 0.0f, 1.0f), // Fatal
|
||
|
|
FLinearColor(1.0f, 0.3f, 0.0f, 1.0f), // Error
|
||
|
|
FLinearColor(0.7f, 0.5f, 0.0f, 1.0f), // Warning
|
||
|
|
FLinearColor(0.0f, 0.7f, 0.0f, 1.0f), // Display
|
||
|
|
FLinearColor(0.0f, 0.7f, 1.0f, 1.0f), // Log
|
||
|
|
FLinearColor(0.7f, 0.7f, 0.7f, 1.0f), // Verbose
|
||
|
|
FLinearColor(1.0f, 1.0f, 1.0f, 1.0f), // VeryVerbose
|
||
|
|
};
|
||
|
|
static_assert(sizeof(Colors) / sizeof(FLinearColor) == (int)ELogVerbosity::Type::All + 1, "ELogVerbosity::Type has changed!?");
|
||
|
|
// return Colors[Verbosity & ELogVerbosity::VerbosityMask];
|
||
|
|
return Colors[Verbosity & 7]; // using 7 instead of ELogVerbosity::VerbosityMask (15) to make static analyzer happy
|
||
|
|
}
|
||
|
|
|
||
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
|
|
||
|
|
void FTimeMarkerTrackBuilder::Flush(float AvailableTextW)
|
||
|
|
{
|
||
|
|
// Is last marker valid?
|
||
|
|
if (LastCategory != nullptr)
|
||
|
|
{
|
||
|
|
const FLinearColor Color = GetColorByCategory(LastCategory);
|
||
|
|
|
||
|
|
bool bAddNewBox = true;
|
||
|
|
if (Track.TimeMarkerBoxes.Num() > 0)
|
||
|
|
{
|
||
|
|
FTimeMarkerBoxInfo& PrevBox = Track.TimeMarkerBoxes[Track.TimeMarkerBoxes.Num() - 1];
|
||
|
|
if (PrevBox.X + PrevBox.W == LastX1 &&
|
||
|
|
PrevBox.Color.R == Color.R &&
|
||
|
|
PrevBox.Color.G == Color.G &&
|
||
|
|
PrevBox.Color.B == Color.B)
|
||
|
|
{
|
||
|
|
// Extend previous box instead.
|
||
|
|
PrevBox.W += LastX2 - LastX1;
|
||
|
|
bAddNewBox = false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if (bAddNewBox)
|
||
|
|
{
|
||
|
|
// Add new Box info to cache.
|
||
|
|
FTimeMarkerBoxInfo& Box = Track.TimeMarkerBoxes[Track.TimeMarkerBoxes.AddDefaulted()];
|
||
|
|
Box.X = LastX1;
|
||
|
|
Box.W = LastX2 - LastX1;
|
||
|
|
Box.Color = Color;
|
||
|
|
Box.Color.A = 0.25f;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (AvailableTextW > 6.0f)
|
||
|
|
{
|
||
|
|
// Strip the "Log" prefix.
|
||
|
|
FString CategoryStr(LastCategory);
|
||
|
|
if (CategoryStr.StartsWith(TEXT("Log")))
|
||
|
|
{
|
||
|
|
CategoryStr.RightChopInline(3, false);
|
||
|
|
}
|
||
|
|
|
||
|
|
const int32 LastWholeCharacterIndexCategory = FontMeasureService->FindLastWholeCharacterIndexBeforeOffset(CategoryStr, Font, FMath::RoundToInt(AvailableTextW - 2.0f));
|
||
|
|
const int32 LastWholeCharacterIndexMessage = FontMeasureService->FindLastWholeCharacterIndexBeforeOffset(LastMessage, Font, FMath::RoundToInt(AvailableTextW - 2.0f));
|
||
|
|
|
||
|
|
if (LastWholeCharacterIndexCategory >= 0 ||
|
||
|
|
LastWholeCharacterIndexMessage >= 0)
|
||
|
|
{
|
||
|
|
// Add new Text info to cache.
|
||
|
|
FTimeMarkerTextInfo& TextInfo = Track.TimeMarkerTexts[Track.TimeMarkerTexts.AddDefaulted()];
|
||
|
|
TextInfo.X = LastX2 + 2.0f;
|
||
|
|
TextInfo.Color = Color;
|
||
|
|
if (LastWholeCharacterIndexCategory >= 0)
|
||
|
|
{
|
||
|
|
TextInfo.Category = CategoryStr.Left(LastWholeCharacterIndexCategory + 1);
|
||
|
|
}
|
||
|
|
if (LastWholeCharacterIndexMessage >= 0)
|
||
|
|
{
|
||
|
|
TextInfo.Message.AppendChars(LastMessage, LastWholeCharacterIndexMessage + 1);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
|
|
||
|
|
void FTimeMarkerTrackBuilder::AddTimeMarker(const float X, const uint64 LogIndex, const ELogVerbosity::Type Verbosity, const TCHAR* const Category, const TCHAR* Message)
|
||
|
|
{
|
||
|
|
const float W = X - LastX2;
|
||
|
|
|
||
|
|
if (W > 0.0f) // There is at least 1px from previous box?
|
||
|
|
{
|
||
|
|
// Flush previous marker (if any).
|
||
|
|
Flush(W);
|
||
|
|
|
||
|
|
// Begin new marker info.
|
||
|
|
LastX1 = X;
|
||
|
|
LastX2 = X + 1.0f;
|
||
|
|
}
|
||
|
|
else if (W == 0.0f) // Adjacent to previous box?
|
||
|
|
{
|
||
|
|
// Same color as previous marker?
|
||
|
|
if (Category == LastCategory)
|
||
|
|
{
|
||
|
|
// Extend previous box.
|
||
|
|
LastX2++;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
// Flush previous marker (if any).
|
||
|
|
Flush(0.0f);
|
||
|
|
|
||
|
|
// Begin new box.
|
||
|
|
LastX1 = X;
|
||
|
|
LastX2 = X + 1.0f;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else // Overlaps previous box?
|
||
|
|
{
|
||
|
|
// Same color as previous marker?
|
||
|
|
if (Category == LastCategory)
|
||
|
|
{
|
||
|
|
// Keep previous box.
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
// Shrink previous box.
|
||
|
|
LastX2--;
|
||
|
|
|
||
|
|
if (LastX2 > LastX1)
|
||
|
|
{
|
||
|
|
// Flush previous marker (if any).
|
||
|
|
Flush(0.0f);
|
||
|
|
}
|
||
|
|
|
||
|
|
// Begin new box.
|
||
|
|
LastX1 = X;
|
||
|
|
LastX2 = X + 1.0f;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Save marker.
|
||
|
|
LastCategory = Category;
|
||
|
|
LastVerbosity = Verbosity;
|
||
|
|
LastLogIndex = LogIndex;
|
||
|
|
LastMessage = Message;
|
||
|
|
}
|
||
|
|
|
||
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
|
|
||
|
|
void FTimeMarkerTrackBuilder::EndLog()
|
||
|
|
{
|
||
|
|
Flush(Viewport.GetWidth() - LastX2);
|
||
|
|
}
|
||
|
|
|
||
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
|
|
||
|
|
#undef LOCTEXT_NAMESPACE
|