1
0
Fork 0
mirror of https://github.com/gwm17/implot.git synced 2024-11-23 02:38:53 -05:00

fix crashing caused by legend refactors, add ShowMetricsWindow (WIP)

This commit is contained in:
epezent 2020-10-21 10:08:41 -05:00
parent eb935d0b4f
commit 96e0fd9c57
5 changed files with 89 additions and 39 deletions

View File

@ -132,14 +132,16 @@ ImPlotStyle::ImPlotStyle() {
UseISO8601 = false;
}
ImPlotItem* ImPlotLegend::GetItem(int i) {
return Plot->Items.GetByIndex(Indices[i]);
ImPlotItem* ImPlotPlot::GetLegendItem(int i) {
IM_ASSERT(Items.GetSize() > 0);
return Items.GetByIndex(LegendData.Indices[i]);
}
const char* ImPlotLegend::GetLabel(int i) {
ImPlotItem* item = GetItem(i);
IM_ASSERT(item->NameOffset != -1 && item->NameOffset < Labels.Buf.Size);
return Labels.Buf.Data + item->NameOffset;
const char* ImPlotPlot::GetLegendLabel(int i) {
ImPlotItem* item = GetLegendItem(i);
IM_ASSERT(item != NULL);
IM_ASSERT(item->NameOffset != -1 && item->NameOffset < LegendData.Labels.Buf.Size);
return LegendData.Labels.Buf.Data + item->NameOffset;
}
//-----------------------------------------------------------------------------
@ -541,16 +543,16 @@ ImVec2 GetLocationPos(const ImRect& outer_rect, const ImVec2& inner_size, ImPlot
return pos;
}
ImVec2 CalcLegendSize(ImPlotLegend& legend, const ImVec2& pad, const ImVec2& spacing, ImPlotOrientation orn) {
ImVec2 CalcLegendSize(ImPlotPlot& plot, const ImVec2& pad, const ImVec2& spacing, ImPlotOrientation orn) {
// vars
const int nItems = legend.Count();
const int nItems = plot.GetLegendCount();
const float txt_ht = ImGui::GetTextLineHeight();
const float icon_size = txt_ht;
// get label max width
float max_label_width = 0;
float sum_label_width = 0;
for (int i = 0; i < nItems; ++i) {
const char* label = legend.GetLabel(i);
const char* label = plot.GetLegendLabel(i);
const float label_width = ImGui::CalcTextSize(label, NULL, true).x;
max_label_width = label_width > max_label_width ? label_width : max_label_width;
sum_label_width += label_width;
@ -562,7 +564,7 @@ ImVec2 CalcLegendSize(ImPlotLegend& legend, const ImVec2& pad, const ImVec2& spa
return legend_size;
}
void ShowLegendEntries(ImPlotLegend& legend, const ImRect& legend_bb, bool interactable, const ImVec2& pad, const ImVec2& spacing, ImPlotOrientation orn, ImDrawList& DrawList) {
void ShowLegendEntries(ImPlotPlot& plot, const ImRect& legend_bb, bool interactable, const ImVec2& pad, const ImVec2& spacing, ImPlotOrientation orn, ImDrawList& DrawList) {
ImGuiIO& IO = ImGui::GetIO();
// vars
const float txt_ht = ImGui::GetTextLineHeight();
@ -572,9 +574,9 @@ void ShowLegendEntries(ImPlotLegend& legend, const ImRect& legend_bb, bool inter
ImU32 col_txt_dis = ImGui::GetColorU32(col_txt * ImVec4(1,1,1,0.25f));
// render each legend item
float sum_label_width = 0;
for (int i = 0; i < legend.Count(); ++i) {
ImPlotItem* item = legend.GetItem(i);
const char* label = legend.GetLabel(i);
for (int i = 0; i < plot.GetLegendCount(); ++i) {
ImPlotItem* item = plot.GetLegendItem(i);
const char* label = plot.GetLegendLabel(i);
const float label_width = ImGui::CalcTextSize(label, NULL, true).x;
const ImVec2 top_left = orn == ImPlotOrientation_Vertical ?
legend_bb.Min + pad + ImVec2(0, i * (txt_ht + spacing.y)) :
@ -1238,9 +1240,10 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons
const ImGuiStyle &Style = G.Style;
const ImGuiIO & IO = ImGui::GetIO();
bool just_created = gp.Plots.GetByKey(ID) == NULL;
gp.CurrentPlot = gp.Plots.GetOrAddByKey(ID);
ImPlotPlot &plot = *gp.CurrentPlot;
bool just_created = gp.Plots.GetByKey(ID) == NULL;
gp.CurrentPlot = gp.Plots.GetOrAddByKey(ID);
gp.CurrentPlot->ID = ID;
ImPlotPlot &plot = *gp.CurrentPlot;
plot.CurrentYAxis = 0;
@ -1366,8 +1369,8 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons
gp.BB_Axes = gp.BB_Frame;
// outside legend adjustments
if (!ImHasFlag(plot.Flags, ImPlotFlags_NoLegend) && plot.Legend.Count() > 0 && plot.LegendOutside) {
const ImVec2 legend_size = CalcLegendSize(plot.Legend, gp.Style.LegendInnerPadding, gp.Style.LegendSpacing, plot.LegendOrientation);
if (!ImHasFlag(plot.Flags, ImPlotFlags_NoLegend) && plot.GetLegendCount() > 0 && plot.LegendOutside) {
const ImVec2 legend_size = CalcLegendSize(plot, gp.Style.LegendInnerPadding, gp.Style.LegendSpacing, plot.LegendOrientation);
const bool west = ImHasFlag(plot.LegendLocation, ImPlotLocation_West) && !ImHasFlag(plot.LegendLocation, ImPlotLocation_East);
const bool east = ImHasFlag(plot.LegendLocation, ImPlotLocation_East) && !ImHasFlag(plot.LegendLocation, ImPlotLocation_West);
const bool north = ImHasFlag(plot.LegendLocation, ImPlotLocation_North) && !ImHasFlag(plot.LegendLocation, ImPlotLocation_South);
@ -1822,7 +1825,7 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons
}
ImGui::PopClipRect();
// clear legend
plot.Legend.Reset();
plot.LegendData.Reset();
// push plot ID into stack
ImGui::PushID(ID);
return true;
@ -2293,8 +2296,8 @@ void EndPlot() {
for (int i = 0; i < plot.Items.GetSize(); ++i)
plot.Items.GetByIndex(i)->LegendHovered = false;
// render legend
if (!ImHasFlag(plot.Flags, ImPlotFlags_NoLegend) && plot.Legend.Count() > 0) {
const ImVec2 legend_size = CalcLegendSize(plot.Legend, gp.Style.LegendInnerPadding, gp.Style.LegendSpacing, plot.LegendOrientation);
if (!ImHasFlag(plot.Flags, ImPlotFlags_NoLegend) && plot.GetLegendCount() > 0) {
const ImVec2 legend_size = CalcLegendSize(plot, gp.Style.LegendInnerPadding, gp.Style.LegendSpacing, plot.LegendOrientation);
const ImVec2 legend_pos = GetLocationPos(plot.LegendOutside ? gp.BB_Frame : gp.BB_Plot,
legend_size,
plot.LegendLocation,
@ -2311,7 +2314,7 @@ void EndPlot() {
ImU32 col_bd = GetStyleColorU32(ImPlotCol_LegendBorder);
DrawList.AddRectFilled(legend_bb.Min, legend_bb.Max, col_bg);
DrawList.AddRect(legend_bb.Min, legend_bb.Max, col_bd);
ShowLegendEntries(plot.Legend, legend_bb, plot.LegendHovered, gp.Style.LegendInnerPadding, gp.Style.LegendSpacing, plot.LegendOrientation, DrawList);
ShowLegendEntries(plot, legend_bb, plot.LegendHovered, gp.Style.LegendInnerPadding, gp.Style.LegendSpacing, plot.LegendOrientation, DrawList);
ImGui::PopClipRect();
}
if (plot.LegendFlipSide) {
@ -2899,7 +2902,7 @@ void ShowAltLegend(const char* title_id, ImPlotOrientation orientation, const Im
ImVec2 legend_size;
ImVec2 default_size = gp.Style.LegendPadding * 2;
if (plot != NULL) {
legend_size = CalcLegendSize(plot->Legend, gp.Style.LegendInnerPadding, gp.Style.LegendSpacing, orientation);
legend_size = CalcLegendSize(*plot, gp.Style.LegendInnerPadding, gp.Style.LegendSpacing, orientation);
default_size = legend_size + gp.Style.LegendPadding * 2;
}
ImVec2 frame_size = ImGui::CalcItemSize(size, default_size.x, default_size.y);
@ -2919,7 +2922,7 @@ void ShowAltLegend(const char* title_id, ImPlotOrientation orientation, const Im
DrawList.AddRectFilled(legend_bb.Min, legend_bb.Max, col_bg);
DrawList.AddRect(legend_bb.Min, legend_bb.Max, col_bd);
// render entries
ShowLegendEntries(plot->Legend, legend_bb, interactable, gp.Style.LegendInnerPadding, gp.Style.LegendSpacing, orientation, DrawList);
ShowLegendEntries(*plot, legend_bb, interactable, gp.Style.LegendInnerPadding, gp.Style.LegendSpacing, orientation, DrawList);
}
DrawList.PopClipRect();
}
@ -3630,6 +3633,47 @@ void ShowUserGuide() {
ImGui::BulletText("Click legend label icons to show/hide plot items.");
}
void ShowMetricsWindow(bool* p_popen) {
ImPlotContext& gp = *GImPlot;
// ImGuiContext& g = *GImGui;
ImGuiIO& io = ImGui::GetIO();
ImGui::Begin("ImPlot Metrics", p_popen);
ImGui::Text("ImPlot " IMPLOT_VERSION);
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate);
ImGui::Text("%d vertices, %d indices (%d triangles)", io.MetricsRenderVertices, io.MetricsRenderIndices, io.MetricsRenderIndices / 3);
ImGui::Separator();
int n_plots = gp.Plots.GetSize();
if (ImGui::TreeNode("Plots","Plots (%d)", n_plots)) {
for (int p = 0; p < n_plots; ++p) {
ImPlotPlot* plot = gp.Plots.GetByIndex(p);
ImGui::PushID(p);
if (ImGui::TreeNode("Plot", "Plot [ID=%u]", plot->ID)) {
int n_items = plot->Items.GetSize();
if (ImGui::TreeNode("Items", "Items (%d)", n_items)) {
for (int i = 0; i < n_items; ++i) {
ImPlotItem* item = plot->Items.GetByIndex(i);
ImGui::PushID(i);
if (ImGui::TreeNode("Item", "Item [ID=%u]", item->ID)) {
ImGui::Bullet(); ImGui::Checkbox("Show", &item->Show);
ImGui::Bullet(); ImGui::ColorEdit4("Color",&item->Color.x, ImGuiColorEditFlags_NoInputs);
ImGui::Bullet(); ImGui::Value("NameOffset",item->NameOffset);
ImGui::Bullet(); ImGui::Text("Name: %s", item->NameOffset != -1 ? plot->LegendData.Labels.Buf.Data + item->NameOffset : "N/A");
ImGui::Bullet(); ImGui::Value("Hovered",item->LegendHovered);
ImGui::TreePop();
}
ImGui::PopID();
}
ImGui::TreePop();
}
ImGui::TreePop();
}
ImGui::PopID();
}
ImGui::TreePop();
}
ImGui::End();
}
bool ShowDatePicker(const char* id, int* level, ImPlotTime* t, const ImPlotTime* t1, const ImPlotTime* t2) {
ImGui::PushID(id);

View File

@ -669,6 +669,8 @@ IMPLOT_API bool ShowColormapSelector(const char* label);
IMPLOT_API void ShowStyleEditor(ImPlotStyle* ref = NULL);
// Add basic help/info block (not a window): how to manipulate ImPlot as an end-user.
IMPLOT_API void ShowUserGuide();
// Shows ImPlot metrics/debug information.
IMPLOT_API void ShowMetricsWindow(bool* p_popen = NULL);
// Sets the current _ImGui_ context. This is ONLY necessary if you are compiling
// ImPlot as a DLL (not recommended) separate from your ImGui compilation. It

View File

@ -136,12 +136,16 @@ struct HugeTimeData {
void ShowDemoWindow(bool* p_open) {
double DEMO_TIME = ImGui::GetTime();
static bool show_imgui_metrics = false;
static bool show_implot_metrics = false;
static bool show_imgui_style_editor = false;
static bool show_implot_style_editor = false;
static bool show_implot_benchmark = false;
if (show_imgui_metrics) {
ImGui::ShowMetricsWindow(&show_imgui_metrics);
}
if (show_implot_metrics) {
ImPlot::ShowMetricsWindow(&show_implot_metrics);
}
if (show_imgui_style_editor) {
ImGui::Begin("Style Editor (ImGui)", &show_imgui_style_editor);
ImGui::ShowStyleEditor();
@ -166,6 +170,7 @@ void ShowDemoWindow(bool* p_open) {
if (ImGui::BeginMenuBar()) {
if (ImGui::BeginMenu("Tools")) {
ImGui::MenuItem("Metrics (ImGui)", NULL, &show_imgui_metrics);
ImGui::MenuItem("Metrics (ImPlot)", NULL, &show_implot_metrics);
ImGui::MenuItem("Style Editor (ImGui)", NULL, &show_imgui_style_editor);
ImGui::MenuItem("Style Editor (ImPlot)", NULL, &show_implot_style_editor);
ImGui::MenuItem("Benchmark", NULL, &show_implot_benchmark);

View File

@ -51,7 +51,7 @@ struct ImPlotAxis;
struct ImPlotAxisState;
struct ImPlotAxisColor;
struct ImPlotItem;
struct ImPlotLegend;
struct ImPlotLegendData;
struct ImPlotPlot;
struct ImPlotNextPlotData;
@ -515,27 +515,22 @@ struct ImPlotItem
};
// Holds Legend state labels and item references
struct ImPlotLegend
struct ImPlotLegendData
{
ImPlotPlot* Plot;
ImVector<int> Indices;
ImGuiTextBuffer Labels;
ImPlotLegend(ImPlotPlot* plot) { Plot = plot; }
void Reset() { Indices.shrink(0); Labels.Buf.shrink(0); }
int Count() const { return Indices.size(); }
ImPlotItem* GetItem(int i);
const char* GetLabel(int i);
};
// Holds Plot state information that must persist after EndPlot
struct ImPlotPlot
{
ImGuiID ID;
ImPlotFlags Flags;
ImPlotFlags PreviousFlags;
ImPlotAxis XAxis;
ImPlotAxis YAxis[IMPLOT_Y_AXES];
ImPlotLegend Legend;
ImPlotLegendData LegendData;
ImPool<ImPlotItem> Items;
ImVec2 SelectStart;
ImVec2 QueryStart;
@ -553,7 +548,7 @@ struct ImPlotPlot
ImPlotLocation LegendLocation;
ImPlotOrientation LegendOrientation;
ImPlotPlot() : Legend(this) {
ImPlotPlot() {
Flags = PreviousFlags = ImPlotFlags_None;
XAxis.Direction = ImPlotOrientation_Horizontal;
for (int i = 0; i < IMPLOT_Y_AXES; ++i)
@ -566,6 +561,9 @@ struct ImPlotPlot
MousePosLocation = ImPlotLocation_South | ImPlotLocation_East;
}
int GetLegendCount() const { return LegendData.Indices.size(); }
ImPlotItem* GetLegendItem(int i);
const char* GetLegendLabel(int i);
};
// Temporary data storage for upcoming plot
@ -803,9 +801,9 @@ IMPLOT_API void ShowAxisContextMenu(ImPlotAxisState& state, bool time_allowed =
// Gets the position of an inner rect that is located inside of an outer rect according to an ImPlotLocation and padding amount.
IMPLOT_API ImVec2 GetLocationPos(const ImRect& outer_rect, const ImVec2& inner_size, ImPlotLocation location, const ImVec2& pad = ImVec2(0,0));
// Calculates the bounding box size of a legend
IMPLOT_API ImVec2 CalcLegendSize(ImPlotLegend& legend, const ImVec2& pad, const ImVec2& spacing, ImPlotOrientation orientation);
IMPLOT_API ImVec2 CalcLegendSize(ImPlotPlot& plot, const ImVec2& pad, const ImVec2& spacing, ImPlotOrientation orientation);
// Renders legend entries into a bounding box
IMPLOT_API void ShowLegendEntries(ImPlotLegend& legend, const ImRect& legend_bb, bool interactable, const ImVec2& pad, const ImVec2& spacing, ImPlotOrientation orientation, ImDrawList& DrawList);
IMPLOT_API void ShowLegendEntries(ImPlotPlot& plot, const ImRect& legend_bb, bool interactable, const ImVec2& pad, const ImVec2& spacing, ImPlotOrientation orientation, ImDrawList& DrawList);
// Shows an alternate legend for the plot identified by #title_id, outside of the plot frame (can be called before or after of Begin/EndPlot but must occur in the same ImGui window!).
IMPLOT_API void ShowAltLegend(const char* title_id, ImPlotOrientation orientation = ImPlotOrientation_Vertical, const ImVec2 size = ImVec2(0,0), bool interactable = true);

View File

@ -60,9 +60,9 @@ ImPlotItem* RegisterOrGetItem(const char* label_id, bool* just_created) {
int idx = gp.CurrentPlot->Items.GetIndex(item);
item->ID = id;
if (ImGui::FindRenderedTextEnd(label_id, NULL) != label_id) {
gp.CurrentPlot->Legend.Indices.push_back(idx);
item->NameOffset = gp.CurrentPlot->Legend.Labels.size();
gp.CurrentPlot->Legend.Labels.append(label_id, label_id + strlen(label_id) + 1);
gp.CurrentPlot->LegendData.Indices.push_back(idx);
item->NameOffset = gp.CurrentPlot->LegendData.Labels.size();
gp.CurrentPlot->LegendData.Labels.append(label_id, label_id + strlen(label_id) + 1);
}
else {
item->Show = true;
@ -131,6 +131,7 @@ void BustItemCache() {
ImPlotPlot& plot = *gp.Plots.GetByIndex(p);
plot.ColormapIdx = 0;
plot.Items.Clear();
plot.LegendData.Reset();
}
}