CogEngine: Plot window improvements.

This commit is contained in:
Arnaud Jamin
2023-11-04 23:20:21 -04:00
parent 9d3143298b
commit 860c9be349
4 changed files with 592 additions and 425 deletions
@@ -7,14 +7,33 @@
#include "implot_internal.h" #include "implot_internal.h"
#include "Kismet/GameplayStatics.h" #include "Kismet/GameplayStatics.h"
//--------------------------------------------------------------------------------------------------------------------------
void FCogEngineWindow_Plots::Initialize()
{
Super::Initialize();
bHasMenu = true;
Config = GetConfig<UCogEngineConfig_Plots>();
}
//-------------------------------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------------------------------
void FCogEngineWindow_Plots::RenderHelp() void FCogEngineWindow_Plots::RenderHelp()
{ {
ImGui::Text( ImGui::Text(
"This window plots values overtime. When applicable, only the values of the selected actor are displayed." "This window plots values and events overtime. When applicable, only the values of the selected actor are displayed."
); );
} }
//--------------------------------------------------------------------------------------------------------------------------
void FCogEngineWindow_Plots::ResetConfig()
{
Super::ResetConfig();
Config->Reset();
}
//-------------------------------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------------------------------
void FCogEngineWindow_Plots::RenderTick(float DeltaTime) void FCogEngineWindow_Plots::RenderTick(float DeltaTime)
{ {
@@ -27,53 +46,258 @@ void FCogEngineWindow_Plots::RenderContent()
{ {
Super::RenderContent(); Super::RenderContent();
static int Rows = 1; RenderMenu();
static int Cols = 1;
if (ImGui::BeginTable("PlotTable", 2, ImGuiTableFlags_RowBg | ImGuiTableFlags_Resizable)) if (ImGui::BeginTable("PlotTable", 2, ImGuiTableFlags_RowBg | ImGuiTableFlags_Resizable))
{ {
ImGui::TableSetupColumn("Settings", ImGuiTableColumnFlags_WidthFixed, FCogWindowWidgets::GetFontWidth() * 20.0f); ImGui::TableSetupColumn("PlotsList", ImGuiTableColumnFlags_WidthFixed, FCogWindowWidgets::GetFontWidth() * 20.0f);
ImGui::TableSetupColumn("Graph", ImGuiTableColumnFlags_WidthStretch, 0.0f); ImGui::TableSetupColumn("Plots", ImGuiTableColumnFlags_WidthStretch, 0.0f);
ImGui::TableNextRow(); ImGui::TableNextRow();
//-------------------------------------------------------------------------------------- TArray<FCogDebugPlotEntry*> VisiblePlots;
// Settings and Entries
//--------------------------------------------------------------------------------------
ImGui::TableNextColumn(); ImGui::TableNextColumn();
if (ImGui::Button("Settings")) RenderPlotsList(VisiblePlots);
{
ImGui::OpenPopup("SettingsPopup"); ImGui::TableNextColumn();
RenderPlots(VisiblePlots);
ImGui::EndTable();
} }
ImGui::SameLine();
FCogWindowWidgets::ToggleButton(&FCogDebugPlot::Pause, "Pause", "Pause", ImVec4(1.0f, 0.0f, 0.0f, 1.0f), ImVec4(0.5f, 0.5f, 0.5f, 1.0f));
if (ImGui::BeginPopup("SettingsPopup")) bApplyTimeScale = false;
}
//--------------------------------------------------------------------------------------------------------------------------
void FCogEngineWindow_Plots::RenderMenu()
{ {
ImGui::SliderInt("Rows", &Rows, 1, 5); if (ImGui::BeginMenuBar())
{
if (ImGui::Button("Clear Data", ImVec2(-1, 0))) if (ImGui::BeginMenu("Options"))
{
if (ImGui::MenuItem("Clear Data"))
{ {
FCogDebugPlot::Clear(); FCogDebugPlot::Clear();
} }
if (ImGui::Button("Reset Layout", ImVec2(-1, 0))) if (ImGui::MenuItem("Reset"))
{ {
FCogDebugPlot::Pause = false; FCogDebugPlot::Pause = false;
Rows = 1;
FCogDebugPlot::Reset(); FCogDebugPlot::Reset();
ResetConfig();
} }
ImGui::EndPopup();
}
if (ImGui::BeginChild("Separator", ImVec2(0, 2)))
{
ImGui::Separator(); ImGui::Separator();
FCogWindowWidgets::SetNextItemToShortWidth();
if (ImGui::SliderInt("Rows", &Config->Rows, 1, 5))
{
bApplyTimeScale = true;
}
FCogWindowWidgets::SetNextItemToShortWidth();
if (ImGui::SliderFloat("Time Range", &Config->TimeRange, 1.0f, 30.0f, "%0.1f"))
{
bApplyTimeScale = true;
}
ImGui::EndMenu();
}
FCogWindowWidgets::ToggleMenuButton(&FCogDebugPlot::Pause, "Pause", ImVec4(1.0f, 0.0f, 0.0f, 1.0f));
ImGui::EndMenuBar();
}
}
//--------------------------------------------------------------------------------------------------------------------------
void FCogEngineWindow_Plots::RenderPlots(const TArray<FCogDebugPlotEntry*>& VisiblePlots)
{
if (ImGui::BeginChild("Graph", ImVec2(0, -1)))
{
static float RowRatios[] = { 1, 1, 1, 1, 1, 1 };
static float ColRatios[] = { 1 };
static ImPlotSubplotFlags SubplotsFlags = ImPlotSubplotFlags_LinkCols;
if (ImPlot::BeginSubplots("", Config->Rows, 1, ImVec2(-1, -1), SubplotsFlags, RowRatios, ColRatios))
{
for (int PlotIndex = 0; PlotIndex < Config->Rows; ++PlotIndex)
{
if (ImPlot::BeginPlot("##Plot", ImVec2(-1, 250)))
{
ImPlotAxisFlags HasPlotOnAxisY1 = false;
ImPlotAxisFlags HasPlotOnAxisY2 = false;
ImPlotAxisFlags HasPlotOnAxisY3 = false;
for (FCogDebugPlotEntry* PlotPtr : VisiblePlots)
{
HasPlotOnAxisY1 |= PlotPtr->CurrentYAxis == ImAxis_Y1 && PlotPtr->CurrentRow == PlotIndex;
HasPlotOnAxisY2 |= PlotPtr->CurrentYAxis == ImAxis_Y2 && PlotPtr->CurrentRow == PlotIndex;
HasPlotOnAxisY3 |= PlotPtr->CurrentYAxis == ImAxis_Y3 && PlotPtr->CurrentRow == PlotIndex;
}
ImPlot::SetupAxis(ImAxis_X1, NULL, ImPlotAxisFlags_NoTickLabels | ImPlotAxisFlags_NoGridLines);
ImPlot::SetupAxis(ImAxis_Y1, HasPlotOnAxisY1 ? "" : "[drop here]", (HasPlotOnAxisY1 ? ImPlotAxisFlags_None : (ImPlotAxisFlags_NoTickLabels | ImPlotAxisFlags_NoGridLines)) | ImPlotAxisFlags_AutoFit);
ImPlot::SetupAxis(ImAxis_Y2, HasPlotOnAxisY2 ? "" : "[drop here]", (HasPlotOnAxisY2 ? ImPlotAxisFlags_None : (ImPlotAxisFlags_NoTickLabels | ImPlotAxisFlags_NoGridLines)) | ImPlotAxisFlags_AutoFit | ImPlotAxisFlags_Opposite);
ImPlot::SetupAxis(ImAxis_Y3, HasPlotOnAxisY3 ? "" : "[drop here]", (HasPlotOnAxisY3 ? ImPlotAxisFlags_None : (ImPlotAxisFlags_NoTickLabels | ImPlotAxisFlags_NoGridLines)) | ImPlotAxisFlags_AutoFit | ImPlotAxisFlags_Opposite);
//--------------------------------------------------------------------------------------------------
// Set the initial X axis range. After, it is automatically updated to move with the current time.
//--------------------------------------------------------------------------------------------------
ImPlot::SetupAxisLimits(ImAxis_X1, 0, Config->TimeRange, ImGuiCond_Appearing);
const ImPlotRange& PlotRange = ImPlot::GetCurrentPlot()->Axes[ImAxis_X1].Range;
const float TimeRange = PlotRange.Max - PlotRange.Min;
if (bApplyTimeScale == false)
{
Config->TimeRange = TimeRange;
}
const ImVec2 PlotMin = ImPlot::GetPlotPos();
const ImVec2 PlotSize = ImPlot::GetPlotSize();
const ImVec2 PlotMax = PlotMin + PlotSize;
//----------------------------------------------------------------
// Draw a vertical lines representing the current time and the mouse time
//----------------------------------------------------------------
RenderTimeMarker();
for (FCogDebugPlotEntry* PlotPtr : VisiblePlots)
{
if (PlotPtr == nullptr)
{
continue;
}
FCogDebugPlotEntry& Entry = *PlotPtr;
if (Entry.CurrentRow == PlotIndex)
{
//--------------------------------------------------------------------------------
// Make the time axis move forward automatically, unless the user pauses or zoom.
//--------------------------------------------------------------------------------
if (FCogDebugPlot::Pause == false && ImGui::GetIO().MouseWheel == 0)
{
ImPlot::SetupAxisLimits(ImAxis_X1, Entry.Time - TimeRange, Entry.Time, ImGuiCond_Always);
}
if (bApplyTimeScale)
{
ImPlot::SetupAxisLimits(ImAxis_X1, Entry.Time - Config->TimeRange, Entry.Time, ImGuiCond_Always);
}
ImPlot::SetAxis(Entry.CurrentYAxis);
ImPlot::SetNextLineStyle(IMPLOT_AUTO_COL);
const char* Label = TCHAR_TO_ANSI(*Entry.Name.ToString());
//----------------------------------------------------------------
// Pause the scrolling if the user drag inside
//----------------------------------------------------------------
const ImVec2 Mouse = ImGui::GetMousePos();
if (Mouse.x > PlotMin.x
&& Mouse.y > PlotMin.y
&& Mouse.x < PlotMax.x
&& Mouse.y < PlotMax.y
&& ImGui::GetDragDropPayload() == nullptr)
{
ImVec2 Drag = ImGui::GetMouseDragDelta(0);
if (FMath::Abs(Drag.x) > 10)
{
FCogDebugPlot::Pause = true;
}
}
//-------------------------------------------------------
// Plot Events
//-------------------------------------------------------
const bool IsEventPlot = Entry.Events.Num() > 0;
if (IsEventPlot)
{
RenderEvents(Entry, Label, PlotMin, PlotMax);
}
//-------------------------------------------------------
// Plot Values
//-------------------------------------------------------
else
{
RenderValues(Entry, Label);
}
//-------------------------------------------------------
// Allow legend item labels to be drag and drop sources
//-------------------------------------------------------
if (ImPlot::BeginDragDropSourceItem(Label))
{
const auto EntryName = StringCast<ANSICHAR>(*Entry.Name.ToString());
ImGui::SetDragDropPayload("DragAndDrop", EntryName.Get(), EntryName.Length() + 1);
ImGui::TextUnformatted(EntryName.Get());
ImPlot::EndDragDropSource();
}
}
}
//-------------------------------------------------------
// Allow the main plot area to be a drag and drop target
//-------------------------------------------------------
if (ImPlot::BeginDragDropTargetPlot())
{
if (const ImGuiPayload* Payload = ImGui::AcceptDragDropPayload("DragAndDrop"))
{
if (FCogDebugPlotEntry* Plot = FCogDebugPlot::FindPlot(FName((const char*)Payload->Data)))
{
Plot->AssignAxis(PlotIndex, ImAxis_Y1);
}
}
ImPlot::EndDragDropTarget();
}
//-------------------------------------------------------
// Allow each y-axis to be a drag and drop target
//-------------------------------------------------------
for (int y = ImAxis_Y1; y <= ImAxis_Y3; ++y)
{
if (ImPlot::BeginDragDropTargetAxis(y))
{
if (const ImGuiPayload* Payload = ImGui::AcceptDragDropPayload("DragAndDrop"))
{
if (FCogDebugPlotEntry* Plot = FCogDebugPlot::FindPlot(FName((const char*)Payload->Data)))
{
Plot->AssignAxis(PlotIndex, y);
}
}
ImPlot::EndDragDropTarget();
}
}
//-------------------------------------------------------
// Allow the legend to be a drag and drop target
//-------------------------------------------------------
if (ImPlot::BeginDragDropTargetLegend())
{
if (const ImGuiPayload* Payload = ImGui::AcceptDragDropPayload("DragAndDrop"))
{
if (FCogDebugPlotEntry* Plot = FCogDebugPlot::FindPlot(FName((const char*)Payload->Data)))
{
Plot->AssignAxis(PlotIndex, ImAxis_Y1);
}
}
ImPlot::EndDragDropTarget();
}
ImPlot::EndPlot();
}
}
ImPlot::EndSubplots();
}
} }
ImGui::EndChild(); ImGui::EndChild();
}
TArray<FCogDebugPlotEntry*> VisiblePlots; //--------------------------------------------------------------------------------------------------------------------------
void FCogEngineWindow_Plots::RenderPlotsList(TArray<FCogDebugPlotEntry*>& VisiblePlots)
{
if (ImGui::BeginChild("Plots", ImVec2(0, -1))) if (ImGui::BeginChild("Plots", ImVec2(0, -1)))
{ {
int Index = 0; int Index = 0;
@@ -117,53 +341,15 @@ void FCogEngineWindow_Plots::RenderContent()
} }
ImGui::EndDragDropTarget(); ImGui::EndDragDropTarget();
} }
//--------------------------------------------------------------------------------------
// Graph
//--------------------------------------------------------------------------------------
ImGui::TableNextColumn();
if (ImGui::BeginChild("Graph", ImVec2(0, -1)))
{
static float RowRatios[] = { 1, 1, 1, 1, 1, 1 };
static float ColRatios[] = { 1 };
static ImPlotSubplotFlags SubplotsFlags = ImPlotSubplotFlags_LinkCols;
if (ImPlot::BeginSubplots("", Rows, Cols, ImVec2(-1, -1), SubplotsFlags, RowRatios, ColRatios))
{
for (int PlotIndex = 0; PlotIndex < Rows; ++PlotIndex)
{
if (ImPlot::BeginPlot("##Plot", ImVec2(-1, 250)))
{
ImPlotAxisFlags HasPlotOnAxisY1 = false;
ImPlotAxisFlags HasPlotOnAxisY2 = false;
ImPlotAxisFlags HasPlotOnAxisY3 = false;
for (FCogDebugPlotEntry* PlotPtr : VisiblePlots)
{
HasPlotOnAxisY1 |= PlotPtr->CurrentYAxis == ImAxis_Y1 && PlotPtr->CurrentRow == PlotIndex;
HasPlotOnAxisY2 |= PlotPtr->CurrentYAxis == ImAxis_Y2 && PlotPtr->CurrentRow == PlotIndex;
HasPlotOnAxisY3 |= PlotPtr->CurrentYAxis == ImAxis_Y3 && PlotPtr->CurrentRow == PlotIndex;
} }
ImPlot::SetupAxis(ImAxis_X1, NULL, ImPlotAxisFlags_NoTickLabels | ImPlotAxisFlags_NoGridLines); //--------------------------------------------------------------------------------------------------------------------------
ImPlot::SetupAxis(ImAxis_Y1, HasPlotOnAxisY1 ? "" : "[drop here]", (HasPlotOnAxisY1 ? ImPlotAxisFlags_None : (ImPlotAxisFlags_NoTickLabels | ImPlotAxisFlags_NoGridLines)) | ImPlotAxisFlags_AutoFit); void FCogEngineWindow_Plots::RenderTimeMarker()
ImPlot::SetupAxis(ImAxis_Y2, HasPlotOnAxisY2 ? "" : "[drop here]", (HasPlotOnAxisY2 ? ImPlotAxisFlags_None : (ImPlotAxisFlags_NoTickLabels | ImPlotAxisFlags_NoGridLines)) | ImPlotAxisFlags_AutoFit | ImPlotAxisFlags_Opposite); {
ImPlot::SetupAxis(ImAxis_Y3, HasPlotOnAxisY3 ? "" : "[drop here]", (HasPlotOnAxisY3 ? ImPlotAxisFlags_None : (ImPlotAxisFlags_NoTickLabels | ImPlotAxisFlags_NoGridLines)) | ImPlotAxisFlags_AutoFit | ImPlotAxisFlags_Opposite);
//--------------------------------------------------------------------------------------------------
// Set the initial X axis range. After it is automatically updated to move with the current time.
//--------------------------------------------------------------------------------------------------
ImPlot::SetupAxisLimits(ImAxis_X1, 0, 10.0f, ImGuiCond_Appearing);
const ImPlotRange& Range = ImPlot::GetCurrentPlot()->Axes[ImAxis_X1].Range;
const float AxisXRange = Range.Max - Range.Min;
//----------------------------------------------------------------
// Draw a vertical lines representing the current time and the mouse time
//----------------------------------------------------------------
ImDrawList* PlotDrawList = ImPlot::GetPlotDrawList();
const ImVec2 PlotMin = ImPlot::GetPlotPos(); const ImVec2 PlotMin = ImPlot::GetPlotPos();
const ImVec2 PlotSize = ImPlot::GetPlotSize(); const ImVec2 PlotSize = ImPlot::GetPlotSize();
const ImVec2 PlotMax = ImVec2(PlotMin.x + PlotSize.x, PlotMin.y + PlotSize.y); ImDrawList* PlotDrawList = ImPlot::GetPlotDrawList();
const float PlotTop = PlotMin.y; const float PlotTop = PlotMin.y;
const float TimeBarBottom = PlotTop + PlotSize.y; const float TimeBarBottom = PlotTop + PlotSize.y;
@@ -176,54 +362,49 @@ void FCogEngineWindow_Plots::RenderContent()
PlotDrawList->AddLine(ImVec2(TimeBarX, PlotTop), ImVec2(TimeBarX, TimeBarBottom), IM_COL32(255, 255, 255, 64)); PlotDrawList->AddLine(ImVec2(TimeBarX, PlotTop), ImVec2(TimeBarX, TimeBarBottom), IM_COL32(255, 255, 255, 64));
} }
ImPlot::PopPlotClipRect(); ImPlot::PopPlotClipRect();
for (FCogDebugPlotEntry* PlotPtr : VisiblePlots)
{
if (PlotPtr == nullptr)
{
continue;
} }
FCogDebugPlotEntry& Entry = *PlotPtr; //--------------------------------------------------------------------------------------------------------------------------
void FCogEngineWindow_Plots::RenderValues(FCogDebugPlotEntry& Entry, const char* Label)
if (Entry.CurrentRow == PlotIndex)
{ {
//--------------------------------------------------------------------------------
// Make the time axis move forward automatically, unless the user pauses or zoom.
//--------------------------------------------------------------------------------
if (FCogDebugPlot::Pause == false && ImGui::GetIO().MouseWheel == 0)
{
ImPlot::SetupAxisLimits(ImAxis_X1, Entry.Time - AxisXRange, Entry.Time, ImGuiCond_Always);
}
ImPlot::SetAxis(Entry.CurrentYAxis);
ImPlot::SetNextLineStyle(IMPLOT_AUTO_COL);
const auto Label = StringCast<ANSICHAR>(*Entry.Name.ToString());
//---------------------------------------------------------------- //----------------------------------------------------------------
// Pause the scrolling if the user drag inside // Custom tooltip
//---------------------------------------------------------------- //----------------------------------------------------------------
ImVec2 Mouse = ImGui::GetMousePos(); if (ImPlot::IsPlotHovered())
if (Mouse.x > PlotMin.x
&& Mouse.y > PlotMin.y
&& Mouse.x < PlotMax.x
&& Mouse.y < PlotMax.y
&& ImGui::GetDragDropPayload() == nullptr)
{ {
ImVec2 Drag = ImGui::GetMouseDragDelta(0); float Value;
if (FMath::Abs(Drag.x) > 10) if (Entry.FindValue(ImPlot::GetPlotMousePos().x, Value))
{ {
FCogDebugPlot::Pause = true; ImGui::BeginTooltip();
ImGui::Text("%s: %0.2f", Label, Value);
ImGui::EndTooltip();
} }
} }
//------------------------------------------------------- if (Entry.ShowValuesMarkers)
// Plot Events
//-------------------------------------------------------
const bool IsEventPlot = Entry.Events.Num() > 0;
if (IsEventPlot)
{ {
ImPlot::SetNextMarkerStyle(ImPlotMarker_Circle);
}
ImPlot::PlotLine(Label, &Entry.Values[0].x, &Entry.Values[0].y, Entry.Values.size(), ImPlotLineFlags_None, Entry.ValueOffset, 2 * sizeof(float));
if (ImPlot::BeginLegendPopup(Label))
{
if (ImGui::Button("Clear"))
{
Entry.Clear();
}
ImGui::Checkbox("Show Markers", &Entry.ShowValuesMarkers);
ImPlot::EndLegendPopup();
}
}
//--------------------------------------------------------------------------------------------------------------------------
void FCogEngineWindow_Plots::RenderEvents(FCogDebugPlotEntry& Entry, const char* Label, const ImVec2& PlotMin, const ImVec2& PlotMax)
{
const ImVec2 Mouse = ImGui::GetMousePos();
ImDrawList* PlotDrawList = ImPlot::GetPlotDrawList();
//-------------------------------------------------------------------- //--------------------------------------------------------------------
// Update plot time for events as events are not pushed every frames // Update plot time for events as events are not pushed every frames
//-------------------------------------------------------------------- //--------------------------------------------------------------------
@@ -240,7 +421,7 @@ void FCogEngineWindow_Plots::RenderContent()
ImVector<ImVec2> DummyData; ImVector<ImVec2> DummyData;
DummyData.push_back(ImVec2(0, 0)); DummyData.push_back(ImVec2(0, 0));
DummyData.push_back(ImVec2(0, 8)); DummyData.push_back(ImVec2(0, 8));
ImPlot::PlotLine(Label.Get(), &DummyData[0].x, &DummyData[0].y, DummyData.size(), Entry.ValueOffset, 2 * sizeof(float)); ImPlot::PlotLine(Label, &DummyData[0].x, &DummyData[0].y, DummyData.size(), Entry.ValueOffset, 2 * sizeof(float));
const FCogDebugPlotEvent* HoveredEvent = nullptr; const FCogDebugPlotEvent* HoveredEvent = nullptr;
@@ -282,8 +463,6 @@ void FCogEngineWindow_Plots::RenderContent()
HoveredEvent = &Event; HoveredEvent = &Event;
} }
} }
} }
//------------------------------------------------------- //-------------------------------------------------------
@@ -296,6 +475,14 @@ void FCogEngineWindow_Plots::RenderContent()
//------------------------------------------------------- //-------------------------------------------------------
// Hovered event tooltip // Hovered event tooltip
//------------------------------------------------------- //-------------------------------------------------------
RenderEventTooltip(HoveredEvent, Entry);
ImPlot::PopPlotClipRect();
}
//--------------------------------------------------------------------------------------------------------------------------
void FCogEngineWindow_Plots::RenderEventTooltip(const FCogDebugPlotEvent* HoveredEvent, FCogDebugPlotEntry& Entry)
{
if (ImPlot::IsPlotHovered() && HoveredEvent != nullptr) if (ImPlot::IsPlotHovered() && HoveredEvent != nullptr)
{ {
FCogWindowWidgets::BeginTableTooltip(); FCogWindowWidgets::BeginTableTooltip();
@@ -366,115 +553,4 @@ void FCogEngineWindow_Plots::RenderContent()
} }
FCogWindowWidgets::EndTableTooltip(); FCogWindowWidgets::EndTableTooltip();
} }
ImPlot::PopPlotClipRect();
}
//-------------------------------------------------------
// Plot Values
//-------------------------------------------------------
else
{
//----------------------------------------------------------------
// Custom tooltip
//----------------------------------------------------------------
if (ImPlot::IsPlotHovered())
{
float Value;
if (Entry.FindValue(ImPlot::GetPlotMousePos().x, Value))
{
ImGui::BeginTooltip();
ImGui::Text("%s: %0.2f", Label.Get(), Value);
ImGui::EndTooltip();
}
}
if (Entry.ShowValuesMarkers)
{
ImPlot::SetNextMarkerStyle(ImPlotMarker_Circle);
}
ImPlot::PlotLine(Label.Get(), &Entry.Values[0].x, &Entry.Values[0].y, Entry.Values.size(), ImPlotLineFlags_None, Entry.ValueOffset, 2 * sizeof(float));
if (ImPlot::BeginLegendPopup(Label.Get()))
{
if (ImGui::Button("Clear"))
{
Entry.Clear();
}
ImGui::Checkbox("Show Markers", &Entry.ShowValuesMarkers);
ImPlot::EndLegendPopup();
}
}
//-------------------------------------------------------
// Allow legend item labels to be drag and drop sources
//-------------------------------------------------------
if (ImPlot::BeginDragDropSourceItem(Label.Get()))
{
ImGui::SetDragDropPayload("DragAndDrop", Label.Get(), Label.Length() + 1);
ImGui::TextUnformatted(Label.Get());
ImPlot::EndDragDropSource();
}
}
}
//-------------------------------------------------------
// Allow the main plot area to be a drag and drop target
//-------------------------------------------------------
if (ImPlot::BeginDragDropTargetPlot())
{
if (const ImGuiPayload* Payload = ImGui::AcceptDragDropPayload("DragAndDrop"))
{
if (FCogDebugPlotEntry* Plot = FCogDebugPlot::FindPlot(FName((const char*)Payload->Data)))
{
Plot->AssignAxis(PlotIndex, ImAxis_Y1);
}
}
ImPlot::EndDragDropTarget();
}
//-------------------------------------------------------
// Allow each y-axis to be a drag and drop target
//-------------------------------------------------------
for (int y = ImAxis_Y1; y <= ImAxis_Y3; ++y)
{
if (ImPlot::BeginDragDropTargetAxis(y))
{
if (const ImGuiPayload* Payload = ImGui::AcceptDragDropPayload("DragAndDrop"))
{
if (FCogDebugPlotEntry* Plot = FCogDebugPlot::FindPlot(FName((const char*)Payload->Data)))
{
Plot->AssignAxis(PlotIndex, y);
}
}
ImPlot::EndDragDropTarget();
}
}
//-------------------------------------------------------
// Allow the legend to be a drag and drop target
//-------------------------------------------------------
if (ImPlot::BeginDragDropTargetLegend())
{
if (const ImGuiPayload* Payload = ImGui::AcceptDragDropPayload("DragAndDrop"))
{
if (FCogDebugPlotEntry* Plot = FCogDebugPlot::FindPlot(FName((const char*)Payload->Data)))
{
Plot->AssignAxis(PlotIndex, ImAxis_Y1);
}
}
ImPlot::EndDragDropTarget();
}
ImPlot::EndPlot();
}
}
ImPlot::EndSubplots();
}
}
ImGui::EndChild();
ImGui::EndTable();
}
} }
@@ -2,6 +2,13 @@
#include "CoreMinimal.h" #include "CoreMinimal.h"
#include "CogWindow.h" #include "CogWindow.h"
#include "CogWindowConfig.h"
#include "CogEngineWindow_Plots.generated.h"
struct ImVec2;
struct FCogDebugPlotEvent;
struct FCogDebugPlotEntry;
class UCogEngineConfig_Plots;
class COGENGINE_API FCogEngineWindow_Plots : public FCogWindow class COGENGINE_API FCogEngineWindow_Plots : public FCogWindow
{ {
@@ -9,12 +16,55 @@ class COGENGINE_API FCogEngineWindow_Plots : public FCogWindow
protected: protected:
virtual void Initialize() override;
virtual void RenderHelp() override; virtual void RenderHelp() override;
virtual void ResetConfig() override;
virtual void RenderTick(float DeltaTime) override; virtual void RenderTick(float DeltaTime) override;
virtual void RenderContent() override; virtual void RenderContent() override;
void RenderPlotsList(TArray<FCogDebugPlotEntry*>& VisiblePlots);
void RenderPlots(const TArray<FCogDebugPlotEntry*>& VisiblePlots);
void RenderMenu();
void RenderTimeMarker();
void RenderValues(FCogDebugPlotEntry& Entry, const char* Label);
void RenderEvents(FCogDebugPlotEntry& Entry, const char* Label, const ImVec2& PlotMin, const ImVec2& PlotMax);
void RenderEventTooltip(const FCogDebugPlotEvent* HoveredEvent, FCogDebugPlotEntry& Entry);
TObjectPtr<UCogEngineConfig_Plots> Config = nullptr;
bool bApplyTimeScale = false;
private: private:
}; };
//--------------------------------------------------------------------------------------------------------------------------
UCLASS(Config = Cog)
class UCogEngineConfig_Plots : public UCogWindowConfig
{
GENERATED_BODY()
public:
UPROPERTY(Config)
int Rows = 1;
UPROPERTY(Config)
float TimeRange = 10.0f;
virtual void Reset() override
{
Rows = 1;
TimeRange = 10.0f;
}
};
@@ -72,6 +72,43 @@ void FCogWindowWidgets::ProgressBarCentered(float Fraction, const ImVec2& Size,
} }
} }
//--------------------------------------------------------------------------------------------------------------------------
void FCogWindowWidgets::ToggleMenuButton(bool* Value, const char* Text, const ImVec4& TrueColor)
{
bool IsTrue = *Value;
if (IsTrue)
{
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(TrueColor.x, TrueColor.y, TrueColor.z, TrueColor.w * 0.6f));
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(TrueColor.x, TrueColor.y, TrueColor.z, TrueColor.w * 0.8f));
ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(TrueColor.x, TrueColor.y, TrueColor.z, TrueColor.w * 1.0f));
}
else
{
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0));
}
if (ImGui::Button(Text))
{
*Value = !*Value;
}
if (IsTrue)
{
ImGui::PopStyleColor(3);
}
else
{
ImGui::PopStyleColor(1);
}
}
//--------------------------------------------------------------------------------------------------------------------------
void FCogWindowWidgets::ToggleButton(bool* Value, const char* Text, const ImVec4& TrueColor, const ImVec4& FalseColor, const ImVec2& Size)
{
ToggleButton(Value, Text, Text, TrueColor, FalseColor, Size);
}
//-------------------------------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------------------------------
void FCogWindowWidgets::ToggleButton(bool* Value, const char* TextTrue, const char* TextFalse, const ImVec4& TrueColor, const ImVec4& FalseColor, const ImVec2& Size) void FCogWindowWidgets::ToggleButton(bool* Value, const char* TextTrue, const char* TextFalse, const ImVec4& TrueColor, const ImVec4& FalseColor, const ImVec2& Size)
{ {
@@ -18,6 +18,10 @@ public:
static void ProgressBarCentered(float Fraction, const ImVec2& Size, const char* Overlay); static void ProgressBarCentered(float Fraction, const ImVec2& Size, const char* Overlay);
static void ToggleMenuButton(bool* Value, const char* Text, const ImVec4& TrueColor);
static void ToggleButton(bool* Value, const char* Text, const ImVec4& TrueColor, const ImVec4& FalseColor, const ImVec2& Size = ImVec2(0, 0));
static void ToggleButton(bool* Value, const char* TextTrue, const char* TextFalse, const ImVec4& TrueColor, const ImVec4& FalseColor, const ImVec2& Size = ImVec2(0, 0)); static void ToggleButton(bool* Value, const char* TextTrue, const char* TextFalse, const ImVec4& TrueColor, const ImVec4& FalseColor, const ImVec2& Size = ImVec2(0, 0));
static bool MultiChoiceButton(const char* Label, bool IsSelected, const ImVec2& Size = ImVec2(0, 0)); static bool MultiChoiceButton(const char* Label, bool IsSelected, const ImVec2& Size = ImVec2(0, 0));