diff --git a/TODO.md b/TODO.md index 35b303e..2b6fcdc 100644 --- a/TODO.md +++ b/TODO.md @@ -31,7 +31,6 @@ The list below represents a combination of high-priority work, nice-to-have feat ## Legend -- `ImPlotLegendFlags_SortItems` - `ImPlotLegendFlags_Scroll` - improve legend icons (e.g. adopt markers, gradients, etc) - make legend frame use ButtonBehavior (maybe impossible) diff --git a/implot.cpp b/implot.cpp index 48a3f75..b76ffb7 100644 --- a/implot.cpp +++ b/implot.cpp @@ -580,8 +580,8 @@ ImVec2 CalcLegendSize(ImPlotItemGroup& items, const ImVec2& pad, const ImVec2& s return legend_size; } -int LegendSortingComp(void* _items, const void* _a, const void* _b) { - ImPlotItemGroup* items = (ImPlotItemGroup*)_items; +int LegendSortingComp(const void* _a, const void* _b) { + ImPlotItemGroup* items = GImPlot->SortItems; const int a = *(const int*)_a; const int b = *(const int*)_b; const char* label_a = items->GetLegendLabel(a); @@ -603,18 +603,18 @@ bool ShowLegendEntries(ImPlotItemGroup& items, const ImRect& legend_bb, bool hov const int num_items = items.GetLegendCount(); if (num_items < 1) return hovered; - // ImVector& indices = GImPlot->TempInt1; - // indices.resize(num_items); - // // bool sort = true; - // // if (sort && num_items > 1) { - // // qsort_s(indices.Data, num_items, sizeof(int), LegendSortingComp, &items); - // // } - // // else { - // // for (int i = 0; i < num_items; ++i) - // // indices[i] = i; - // // } + // build render order + ImVector& indices = GImPlot->TempInt1; + indices.resize(num_items); + for (int i = 0; i < num_items; ++i) + indices[i] = i; + if (ImHasFlag(items.Legend.Flags, ImPlotLegendFlags_Sort) && num_items > 1) { + GImPlot->SortItems = &items; + qsort(indices.Data, num_items, sizeof(int), LegendSortingComp); + } + // render for (int i = 0; i < num_items; ++i) { - const int idx = i; //indices[i]; + const int idx = indices[i]; ImPlotItem* item = items.GetLegendItem(idx); const char* label = items.GetLegendLabel(idx); const float label_width = ImGui::CalcTextSize(label, NULL, true).x; diff --git a/implot.h b/implot.h index f4174eb..997d96f 100644 --- a/implot.h +++ b/implot.h @@ -191,6 +191,7 @@ enum ImPlotLegendFlags_ { ImPlotLegendFlags_NoMenus = 1 << 3, // the user will not be able to open context menus with right-click ImPlotLegendFlags_Outside = 1 << 4, // legend will be rendered outside of the plot area ImPlotLegendFlags_Horizontal = 1 << 5, // legend entries will be displayed horizontally + ImPlotLegendFlags_Sort = 1 << 6, // legend entries will be displayed in alphabetical order }; // Options for mouse hover text (see SetupMouseText) diff --git a/implot_demo.cpp b/implot_demo.cpp index 3a62775..19e8143 100644 --- a/implot_demo.cpp +++ b/implot_demo.cpp @@ -1361,31 +1361,35 @@ void Demo_SubplotAxisLinking() { void Demo_LegendOptions() { static ImPlotLocation loc = ImPlotLocation_East; - static bool h = false; static bool o = true; ImGui::CheckboxFlags("North", (unsigned int*)&loc, ImPlotLocation_North); ImGui::SameLine(); ImGui::CheckboxFlags("South", (unsigned int*)&loc, ImPlotLocation_South); ImGui::SameLine(); ImGui::CheckboxFlags("West", (unsigned int*)&loc, ImPlotLocation_West); ImGui::SameLine(); - ImGui::CheckboxFlags("East", (unsigned int*)&loc, ImPlotLocation_East); ImGui::SameLine(); - ImGui::Checkbox("Horizontal##2", &h); ImGui::SameLine(); - ImGui::Checkbox("Outside", &o); + ImGui::CheckboxFlags("East", (unsigned int*)&loc, ImPlotLocation_East); + + static ImPlotLegendFlags flags = 0; + + CHECKBOX_FLAG(flags, ImPlotLegendFlags_Horizontal); + CHECKBOX_FLAG(flags, ImPlotLegendFlags_Outside); + CHECKBOX_FLAG(flags, ImPlotLegendFlags_Sort); ImGui::SliderFloat2("LegendPadding", (float*)&GetStyle().LegendPadding, 0.0f, 20.0f, "%.0f"); ImGui::SliderFloat2("LegendInnerPadding", (float*)&GetStyle().LegendInnerPadding, 0.0f, 10.0f, "%.0f"); ImGui::SliderFloat2("LegendSpacing", (float*)&GetStyle().LegendSpacing, 0.0f, 5.0f, "%.0f"); if (ImPlot::BeginPlot("##Legend",ImVec2(-1,0))) { - ImPlotLegendFlags flags = ImPlotLegendFlags_None; - if (h) flags |= ImPlotLegendFlags_Horizontal; - if (o) flags |= ImPlotLegendFlags_Outside; ImPlot::SetupLegend(loc, flags); - static MyImPlot::WaveData data1(0.001, 0.2, 2, 0.75); - static MyImPlot::WaveData data2(0.001, 0.2, 4, 0.25); - static MyImPlot::WaveData data3(0.001, 0.2, 6, 0.5); - ImPlot::PlotLineG("Item 1", MyImPlot::SineWave, &data1, 1000); // "Item 1" added to legend - ImPlot::PlotLineG("Item 2##IDText", MyImPlot::SawWave, &data2, 1000); // "Item 2" added to legend, text after ## used for ID only + static MyImPlot::WaveData data1(0.001, 0.2, 4, 0.2); + static MyImPlot::WaveData data2(0.001, 0.2, 4, 0.4); + static MyImPlot::WaveData data3(0.001, 0.2, 4, 0.6); + static MyImPlot::WaveData data4(0.001, 0.2, 4, 0.8); + static MyImPlot::WaveData data5(0.001, 0.2, 4, 1.0); + + ImPlot::PlotLineG("Item B", MyImPlot::SawWave, &data1, 1000); // "Item B" added to legend + ImPlot::PlotLineG("Item A##IDText", MyImPlot::SawWave, &data2, 1000); // "Item A" added to legend, text after ## used for ID only ImPlot::PlotLineG("##NotListed", MyImPlot::SawWave, &data3, 1000); // plotted, but not added to legend - ImPlot::PlotLineG("Item 3", MyImPlot::SineWave, &data1, 1000); // "Item 3" added to legend - ImPlot::PlotLineG("Item 3", MyImPlot::SawWave, &data2, 1000); // combined with previous "Item 3" + ImPlot::PlotLineG("Item C", MyImPlot::SawWave, &data4, 1000); // "Item C" added to legend + ImPlot::PlotLineG("Item C", MyImPlot::SawWave, &data5, 1000); // combined with previous "Item C" + ImPlot::EndPlot(); } } diff --git a/implot_internal.h b/implot_internal.h index 92266bd..b2685ff 100644 --- a/implot_internal.h +++ b/implot_internal.h @@ -1244,6 +1244,7 @@ struct ImPlotContext { ImPlotInputMap InputMap; bool OpenContextThisFrame; ImGuiTextBuffer MousePosStringBuilder; + ImPlotItemGroup* SortItems; // Align plots ImPool AlignmentData;