diff --git a/README.md b/README.md index 7e47fd2f..af18ab6d 100644 --- a/README.md +++ b/README.md @@ -139,11 +139,11 @@ A: ImPlot plotting functions accept most scalar types: **Q: Can plot styles be modified?** -A: Yes. Data colormaps and various styling colors and variables can be pushed/popped or modified permanently on startup. Three default styles are available, as well as an automatic style that attempts to match you ImGui style. +A: Yes. Three default styles are available, as well as an automatic style that attempts to match you ImGui style. You can define any custom style as well. Plot items are generally styled for you based on the current colormap, but can be customized on an individual basis. -**Q: Does ImPlot support logarithmic scaling or time formatting?** +**Q: Does ImPlot support non-linear axis scaling? Time formatting?** -A: Yep! Both logscale and timescale are supported. +A: Yes. Logscale and symmetric logscale are provided out of the box, and you can define custom axis scales as well. Time scale with microsecond precision is also available out of the box. **Q: Does ImPlot support multiple y-axes? x-axes?** @@ -151,7 +151,7 @@ A: Yes. Up to three x-axes and three y-axes can be enabled. **Q: Does ImPlot support [insert plot type]?** -A: Maybe. Check the demo, gallery, or Announcements ([2020](https://github.com/epezent/implot/issues/48)/[2021](https://github.com/epezent/implot/issues/168))to see if your desired plot type is shown. If not, consider submitting an issue or better yet, a PR! +A: Maybe. Check the demo, gallery, or Announcements ([2020](https://github.com/epezent/implot/issues/48)/[2021](https://github.com/epezent/implot/issues/168)/[2022](https://github.com/epezent/implot/discussions/370)) to see if your desired plot type is shown. If not, consider submitting an issue or better yet, a PR! **Q: Does ImPlot support 3D plots?** diff --git a/implot.cpp b/implot.cpp index 780936ad..89c7160f 100644 --- a/implot.cpp +++ b/implot.cpp @@ -31,6 +31,14 @@ Below is a change-log of API breaking changes only. If you are using one of the When you are not sure about a old symbol or function name, try using the Search/Find function of your IDE to look for comments or references in all implot files. You can read releases logs https://github.com/epezent/implot/releases for more details. +- 2023/10/02 (0.17) - ImPlotSpec was made the default and _only_ way of styling plot items. Therefore the following features were removed: + - SetNextLineStyle, SetNextFillStyle, SetNextMarkerStyle, and SetNextErrorBarStyle have been removed; pass styling variables directly to PlotX functions now with ImPlotSpec + - ImPlotCol_Line, ImPlotCol_Fill, ImPlotCol_MarkerOutline, ImPlotCol_MarkerFill, ImPlotCol_ErrorBar have been removed and thus are no longer supported by PushStyleColor. + You can use a common ImPlotSpec instance across multiple PlotX calls to emulate PushStyleColor behavior. + - ImPlotStyleVar_LineWeight, ImPlotStyleVar_Marker, ImPlotStyleVar_MarkerSize, ImPlotStyleVar_MarkerWeight, ImPlotStyleVar_FillAlpha, ImPlotStyleVar_ErrorBarSize, and ImPlotStyleVar_ErrorBarWeight + have been removed and thus are no longer supported by PushStyleVar. You can use a common ImPlotSpec instance across multiple PlotX calls to emulate PushStyleVar behavior. + - ImPlotStyle/ImPlotStyleVar_ DigitalBitGap as renamed to DigitalSpacing; DigitalBitHeight was removed (use ImPlotSpec::Size); DigitalPadding was added for padding from bottom. + - PlotX offset, stride, and flags parameters are now incorporated into ImPlotSpec; specify these variables in the ImPlotSpec passed to PlotX. - 2023/08/20 (0.17) - ImPlotFlags_NoChild was removed as child windows are no longer needed to capture scroll. You can safely remove this flag if you were using it. - 2023/06/26 (0.15) - Various build fixes related to updates in Dear ImGui internals. - 2022/11/25 (0.15) - Make PlotText honor ImPlotItemFlags_NoFit. @@ -96,7 +104,7 @@ You can read releases logs https://github.com/epezent/implot/releases for more d - 2020/09/07 (0.8) - Plotting functions which accept a custom getter function pointer have been post-fixed with a G (e.g. PlotLineG) - 2020/09/06 (0.7) - Several flags under ImPlotFlags and ImPlotAxisFlags were inverted (e.g. ImPlotFlags_Legend -> ImPlotFlags_NoLegend) so that the default flagset is simply 0. This more closely matches ImGui's style and makes it easier to enable non-default but commonly used flags (e.g. ImPlotAxisFlags_Time). -- 2020/08/28 (0.5) - ImPlotMarker_ can no longer be combined with bitwise OR, |. This features caused unecessary slow-down, and almost no one used it. +- 2020/08/28 (0.5) - ImPlotMarker_ can no longer be combined with bitwise OR, |. This features caused unnecessary slow-down, and almost no one used it. - 2020/08/25 (0.5) - ImPlotAxisFlags_Scientific was removed. Logarithmic axes automatically uses scientific notation. - 2020/08/17 (0.5) - PlotText was changed so that text is centered horizontally and vertically about the desired point. - 2020/08/16 (0.5) - An ImPlotContext must be explicitly created and destroyed now with `CreateContext` and `DestroyContext`. Previously, the context was statically initialized in this source file. @@ -167,17 +175,8 @@ ImPlotInputMap::ImPlotInputMap() { } ImPlotStyle::ImPlotStyle() { - - LineWeight = 1; - Marker = ImPlotMarker_None; - MarkerSize = 4; - MarkerWeight = 1; - FillAlpha = 1; - ErrorBarSize = 5; - ErrorBarWeight = 1.5f; - DigitalBitHeight = 8; - DigitalBitGap = 4; - + PlotDefaultSize = ImVec2(400,300); + PlotMinSize = ImVec2(200,150); PlotBorderSize = 1; MinorAlpha = 0.25f; MajorTickLen = ImVec2(10,10); @@ -194,9 +193,9 @@ ImPlotStyle::ImPlotStyle() { MousePosPadding = ImVec2(10,10); AnnotationPadding = ImVec2(2,2); FitPadding = ImVec2(0,0); - PlotDefaultSize = ImVec2(400,300); - PlotMinSize = ImVec2(200,150); - + DigitalPadding = 20; + DigitalSpacing = 4; + ImPlot::StyleColorsAuto(this); Colormap = ImPlotColormap_Deep; @@ -214,11 +213,6 @@ namespace ImPlot { const char* GetStyleColorName(ImPlotCol col) { static const char* col_names[ImPlotCol_COUNT] = { - "Line", - "Fill", - "MarkerOutline", - "MarkerFill", - "ErrorBar", "FrameBg", "PlotBg", "PlotBorder", @@ -242,6 +236,7 @@ const char* GetStyleColorName(ImPlotCol col) { const char* GetMarkerName(ImPlotMarker marker) { switch (marker) { case ImPlotMarker_None: return "None"; + case ImPlotMarker_Auto: return "Auto"; case ImPlotMarker_Circle: return "Circle"; case ImPlotMarker_Square: return "Square"; case ImPlotMarker_Diamond: return "Diamond"; @@ -259,11 +254,6 @@ const char* GetMarkerName(ImPlotMarker marker) { ImVec4 GetAutoColor(ImPlotCol idx) { ImVec4 col(0,0,0,1); switch(idx) { - case ImPlotCol_Line: return col; // these are plot dependent! - case ImPlotCol_Fill: return col; // these are plot dependent! - case ImPlotCol_MarkerOutline: return col; // these are plot dependent! - case ImPlotCol_MarkerFill: return col; // these are plot dependent! - case ImPlotCol_ErrorBar: return ImGui::GetStyleColorVec4(ImGuiCol_Text); case ImPlotCol_FrameBg: return ImGui::GetStyleColorVec4(ImGuiCol_FrameBg); case ImPlotCol_PlotBg: return ImGui::GetStyleColorVec4(ImGuiCol_WindowBg); case ImPlotCol_PlotBorder: return ImGui::GetStyleColorVec4(ImGuiCol_Border); @@ -293,16 +283,8 @@ struct ImPlotStyleVarInfo { static const ImPlotStyleVarInfo GPlotStyleVarInfo[] = { - { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImPlotStyle, LineWeight) }, // ImPlotStyleVar_LineWeight - { ImGuiDataType_S32, 1, (ImU32)IM_OFFSETOF(ImPlotStyle, Marker) }, // ImPlotStyleVar_Marker - { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImPlotStyle, MarkerSize) }, // ImPlotStyleVar_MarkerSize - { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImPlotStyle, MarkerWeight) }, // ImPlotStyleVar_MarkerWeight - { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImPlotStyle, FillAlpha) }, // ImPlotStyleVar_FillAlpha - { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImPlotStyle, ErrorBarSize) }, // ImPlotStyleVar_ErrorBarSize - { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImPlotStyle, ErrorBarWeight) }, // ImPlotStyleVar_ErrorBarWeight - { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImPlotStyle, DigitalBitHeight) }, // ImPlotStyleVar_DigitalBitHeight - { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImPlotStyle, DigitalBitGap) }, // ImPlotStyleVar_DigitalBitGap - + { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImPlotStyle, PlotDefaultSize) }, // ImPlotStyleVar_PlotDefaultSize + { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImPlotStyle, PlotMinSize) }, // ImPlotStyleVar_PlotMinSize { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImPlotStyle, PlotBorderSize) }, // ImPlotStyleVar_PlotBorderSize { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImPlotStyle, MinorAlpha) }, // ImPlotStyleVar_MinorAlpha { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImPlotStyle, MajorTickLen) }, // ImPlotStyleVar_MajorTickLen @@ -312,16 +294,15 @@ static const ImPlotStyleVarInfo GPlotStyleVarInfo[] = { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImPlotStyle, MajorGridSize) }, // ImPlotStyleVar_MajorGridSize { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImPlotStyle, MinorGridSize) }, // ImPlotStyleVar_MinorGridSize { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImPlotStyle, PlotPadding) }, // ImPlotStyleVar_PlotPadding - { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImPlotStyle, LabelPadding) }, // ImPlotStyleVar_LabelPaddine + { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImPlotStyle, LabelPadding) }, // ImPlotStyleVar_LabelPadding { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImPlotStyle, LegendPadding) }, // ImPlotStyleVar_LegendPadding { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImPlotStyle, LegendInnerPadding) }, // ImPlotStyleVar_LegendInnerPadding { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImPlotStyle, LegendSpacing) }, // ImPlotStyleVar_LegendSpacing - { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImPlotStyle, MousePosPadding) }, // ImPlotStyleVar_MousePosPadding { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImPlotStyle, AnnotationPadding) }, // ImPlotStyleVar_AnnotationPadding { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImPlotStyle, FitPadding) }, // ImPlotStyleVar_FitPadding - { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImPlotStyle, PlotDefaultSize) }, // ImPlotStyleVar_PlotDefaultSize - { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImPlotStyle, PlotMinSize) } // ImPlotStyleVar_PlotMinSize + { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImPlotStyle, DigitalPadding) }, // ImPlotStyleVar_DigitalPadding + { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImPlotStyle, DigitalSpacing) }, // ImPlotStyleVar_DigitalSpacing }; static const ImPlotStyleVarInfo* GetPlotStyleVarInfo(ImPlotStyleVar idx) { @@ -708,8 +689,8 @@ bool ShowLegendEntries(ImPlotItemGroup& items, const ImRect& legend_bb, bool hov // Locators //----------------------------------------------------------------------------- -static const float TICK_FILL_X = 0.8f; -static const float TICK_FILL_Y = 1.0f; +constexpr float TICK_FILL_X = 0.8f; +constexpr float TICK_FILL_Y = 1.0f; void Locator_Default(ImPlotTicker& ticker, const ImPlotRange& range, float pixels, bool vertical, ImPlotFormatter formatter, void* formatter_data) { if (range.Min == range.Max) @@ -845,7 +826,7 @@ void AddTicksCustom(const double* values, const char* const labels[], int n, ImP //----------------------------------------------------------------------------- // this may not be thread safe? -static const double TimeUnitSpans[ImPlotTimeUnit_COUNT] = { +constexpr double TimeUnitSpans[ImPlotTimeUnit_COUNT] = { 0.000001, 0.001, 1, @@ -857,7 +838,7 @@ static const double TimeUnitSpans[ImPlotTimeUnit_COUNT] = { }; inline ImPlotTimeUnit GetUnitForRange(double range) { - static double cutoffs[ImPlotTimeUnit_COUNT] = {0.001, 1, 60, 3600, 86400, 2629800, 31557600, IMPLOT_MAX_TIME}; + constexpr double cutoffs[ImPlotTimeUnit_COUNT] = {0.001, 1, 60, 3600, 86400, 2629800, 31557600, IMPLOT_MAX_TIME}; for (int i = 0; i < ImPlotTimeUnit_COUNT; ++i) { if (range <= cutoffs[i]) return (ImPlotTimeUnit)i; @@ -877,28 +858,28 @@ inline int LowerBoundStep(int max_divs, const int* divs, const int* step, int si inline int GetTimeStep(int max_divs, ImPlotTimeUnit unit) { if (unit == ImPlotTimeUnit_Ms || unit == ImPlotTimeUnit_Us) { - static const int step[] = {500,250,200,100,50,25,20,10,5,2,1}; - static const int divs[] = {2,4,5,10,20,40,50,100,200,500,1000}; + constexpr int step[] = {500,250,200,100,50,25,20,10,5,2,1}; + constexpr int divs[] = {2,4,5,10,20,40,50,100,200,500,1000}; return LowerBoundStep(max_divs, divs, step, 11); } if (unit == ImPlotTimeUnit_S || unit == ImPlotTimeUnit_Min) { - static const int step[] = {30,15,10,5,1}; - static const int divs[] = {2,4,6,12,60}; + constexpr int step[] = {30,15,10,5,1}; + constexpr int divs[] = {2,4,6,12,60}; return LowerBoundStep(max_divs, divs, step, 5); } else if (unit == ImPlotTimeUnit_Hr) { - static const int step[] = {12,6,3,2,1}; - static const int divs[] = {2,4,8,12,24}; + constexpr int step[] = {12,6,3,2,1}; + constexpr int divs[] = {2,4,8,12,24}; return LowerBoundStep(max_divs, divs, step, 5); } else if (unit == ImPlotTimeUnit_Day) { - static const int step[] = {14,7,2,1}; - static const int divs[] = {2,4,14,28}; + constexpr int step[] = {14,7,2,1}; + constexpr int divs[] = {2,4,14,28}; return LowerBoundStep(max_divs, divs, step, 4); } else if (unit == ImPlotTimeUnit_Mo) { - static const int step[] = {6,3,2,1}; - static const int divs[] = {2,4,6,12}; + constexpr int step[] = {6,3,2,1}; + constexpr int divs[] = {2,4,6,12}; return LowerBoundStep(max_divs, divs, step, 4); } return 0; @@ -1822,8 +1803,8 @@ static inline void RenderSelectionRect(ImDrawList& DrawList, const ImVec2& p_min // Input Handling //----------------------------------------------------------------------------- -static const float MOUSE_CURSOR_DRAG_THRESHOLD = 5.0f; -static const float BOX_SELECT_DRAG_THRESHOLD = 4.0f; +constexpr float MOUSE_CURSOR_DRAG_THRESHOLD = 5.0f; +constexpr float BOX_SELECT_DRAG_THRESHOLD = 4.0f; bool UpdateInput(ImPlotPlot& plot) { @@ -3266,9 +3247,9 @@ void EndPlot() { // BEGIN/END SUBPLOT //----------------------------------------------------------------------------- -static const float SUBPLOT_BORDER_SIZE = 1.0f; -static const float SUBPLOT_SPLITTER_HALF_THICKNESS = 4.0f; -static const float SUBPLOT_SPLITTER_FEEDBACK_TIMER = 0.06f; +constexpr float SUBPLOT_BORDER_SIZE = 1.0f; +constexpr float SUBPLOT_SPLITTER_HALF_THICKNESS = 4.0f; +constexpr float SUBPLOT_SPLITTER_FEEDBACK_TIMER = 0.06f; void SubplotSetCell(int row, int col) { ImPlotContext& gp = *GImPlot; @@ -3624,7 +3605,7 @@ void EndSubplots() { // remove items if (gp.CurrentItems == &subplot.Items) gp.CurrentItems = nullptr; - // reset the plot items for the next frame (TODO: put this elswhere) + // reset the plot items for the next frame (TODO: put this elsewhere) for (int i = 0; i < subplot.Items.GetItemCount(); ++i) { subplot.Items.GetItemByIndex(i)->SeenThisFrame = false; } @@ -3892,7 +3873,7 @@ IMPLOT_API void TagYV(double y, const ImVec4& color, const char* fmt, va_list ar TagV(gp.CurrentPlot->CurrentY, y, color, fmt, args); } -static const float DRAG_GRAB_HALF_SIZE = 4.0f; +constexpr float DRAG_GRAB_HALF_SIZE = 4.0f; bool DragPoint(int n_id, double* x, double* y, const ImVec4& col, float radius, ImPlotDragToolFlags flags, bool* out_clicked, bool* out_hovered, bool* out_held) { ImGui::PushID("#IMPLOT_DRAG_POINT"); @@ -4479,6 +4460,14 @@ void PopStyleVar(int count) { } } +ImPlotMarker NextMarker() { + ImPlotContext& gp = *GImPlot; + IM_ASSERT_USER_ERROR(gp.CurrentItems != nullptr, "NextMarker() needs to be called between BeginPlot() and EndPlot()!"); + const int idx = gp.CurrentItems->MarkerIdx % ImPlotMarker_COUNT; + ++gp.CurrentItems->MarkerIdx; + return idx; +} + //------------------------------------------------------------------------------ // [Section] Colormaps //------------------------------------------------------------------------------ @@ -4552,7 +4541,7 @@ ImU32 NextColormapColorU32() { ImVec4 NextColormapColor() { return ImGui::ColorConvertU32ToFloat4(NextColormapColorU32()); -} +} int GetColormapSize(ImPlotColormap cmap) { ImPlotContext& gp = *GImPlot; @@ -4948,16 +4937,9 @@ void ShowStyleEditor(ImPlotStyle* ref) { "Use \"Export\" below to save them somewhere."); if (ImGui::BeginTabBar("##StyleEditor")) { if (ImGui::BeginTabItem("Variables")) { - ImGui::Text("Item Styling"); - ImGui::SliderFloat("LineWeight", &style.LineWeight, 0.0f, 5.0f, "%.1f"); - ImGui::SliderFloat("MarkerSize", &style.MarkerSize, 2.0f, 10.0f, "%.1f"); - ImGui::SliderFloat("MarkerWeight", &style.MarkerWeight, 0.0f, 5.0f, "%.1f"); - ImGui::SliderFloat("FillAlpha", &style.FillAlpha, 0.0f, 1.0f, "%.2f"); - ImGui::SliderFloat("ErrorBarSize", &style.ErrorBarSize, 0.0f, 10.0f, "%.1f"); - ImGui::SliderFloat("ErrorBarWeight", &style.ErrorBarWeight, 0.0f, 5.0f, "%.1f"); - ImGui::SliderFloat("DigitalBitHeight", &style.DigitalBitHeight, 0.0f, 20.0f, "%.1f"); - ImGui::SliderFloat("DigitalBitGap", &style.DigitalBitGap, 0.0f, 20.0f, "%.1f"); ImGui::Text("Plot Styling"); + ImGui::SliderFloat2("PlotDefaultSize", (float*)&style.PlotDefaultSize, 0.0f, 1000, "%.0f"); + ImGui::SliderFloat2("PlotMinSize", (float*)&style.PlotMinSize, 0.0f, 300, "%.0f"); ImGui::SliderFloat("PlotBorderSize", &style.PlotBorderSize, 0.0f, 2.0f, "%.0f"); ImGui::SliderFloat("MinorAlpha", &style.MinorAlpha, 0.0f, 1.0f, "%.2f"); ImGui::SliderFloat2("MajorTickLen", (float*)&style.MajorTickLen, 0.0f, 20.0f, "%.0f"); @@ -4966,8 +4948,6 @@ void ShowStyleEditor(ImPlotStyle* ref) { ImGui::SliderFloat2("MinorTickSize", (float*)&style.MinorTickSize, 0.0f, 2.0f, "%.1f"); ImGui::SliderFloat2("MajorGridSize", (float*)&style.MajorGridSize, 0.0f, 2.0f, "%.1f"); ImGui::SliderFloat2("MinorGridSize", (float*)&style.MinorGridSize, 0.0f, 2.0f, "%.1f"); - ImGui::SliderFloat2("PlotDefaultSize", (float*)&style.PlotDefaultSize, 0.0f, 1000, "%.0f"); - ImGui::SliderFloat2("PlotMinSize", (float*)&style.PlotMinSize, 0.0f, 300, "%.0f"); ImGui::Text("Plot Padding"); ImGui::SliderFloat2("PlotPadding", (float*)&style.PlotPadding, 0.0f, 20.0f, "%.0f"); ImGui::SliderFloat2("LabelPadding", (float*)&style.LabelPadding, 0.0f, 20.0f, "%.0f"); @@ -4977,7 +4957,8 @@ void ShowStyleEditor(ImPlotStyle* ref) { ImGui::SliderFloat2("MousePosPadding", (float*)&style.MousePosPadding, 0.0f, 20.0f, "%.0f"); ImGui::SliderFloat2("AnnotationPadding", (float*)&style.AnnotationPadding, 0.0f, 5.0f, "%.0f"); ImGui::SliderFloat2("FitPadding", (float*)&style.FitPadding, 0, 0.2f, "%.2f"); - + ImGui::SliderFloat("DigitalPadding", &style.DigitalPadding, 0.0f, 20.0f, "%.1f"); + ImGui::SliderFloat("DigitalSpacing", &style.DigitalSpacing, 0.0f, 10.0f, "%.1f"); ImGui::EndTabItem(); } if (ImGui::BeginTabItem("Colors")) { @@ -5054,9 +5035,7 @@ void ShowStyleEditor(ImPlotStyle* ref) { ImGui::PopItemWidth(); ImGui::Separator(); ImGui::Text("Colors that are set to Auto (i.e. IMPLOT_AUTO_COL) will\n" - "be automatically deduced from your ImGui style or the\n" - "current ImPlot Colormap. If you want to style individual\n" - "plot items, use Push/PopStyleColor around its function."); + "be automatically deduced from your ImGui style."); ImGui::EndTabItem(); } if (ImGui::BeginTabItem("Colormaps")) { @@ -5313,7 +5292,7 @@ void ShowMetricsWindow(bool* p_popen) { ImVec4 temp = ImGui::ColorConvertU32ToFloat4(item->Color); if (ImGui::ColorEdit4("Color",&temp.x, ImGuiColorEditFlags_NoInputs)) item->Color = ImGui::ColorConvertFloat4ToU32(temp); - + ImGui::BulletText("Marker: %s", GetMarkerName(item->Marker)); ImGui::BulletText("NameOffset: %d",item->NameOffset); ImGui::BulletText("Name: %s", item->NameOffset != -1 ? plot.Items.Legend.Labels.Buf.Data + item->NameOffset : "N/A"); ImGui::BulletText("Hovered: %s",item->LegendHovered ? "true" : "false"); @@ -5748,11 +5727,6 @@ void StyleColorsAuto(ImPlotStyle* dst) { style->MinorAlpha = 0.25f; - colors[ImPlotCol_Line] = IMPLOT_AUTO_COL; - colors[ImPlotCol_Fill] = IMPLOT_AUTO_COL; - colors[ImPlotCol_MarkerOutline] = IMPLOT_AUTO_COL; - colors[ImPlotCol_MarkerFill] = IMPLOT_AUTO_COL; - colors[ImPlotCol_ErrorBar] = IMPLOT_AUTO_COL; colors[ImPlotCol_FrameBg] = IMPLOT_AUTO_COL; colors[ImPlotCol_PlotBg] = IMPLOT_AUTO_COL; colors[ImPlotCol_PlotBorder] = IMPLOT_AUTO_COL; @@ -5777,12 +5751,7 @@ void StyleColorsClassic(ImPlotStyle* dst) { ImVec4* colors = style->Colors; style->MinorAlpha = 0.5f; - - colors[ImPlotCol_Line] = IMPLOT_AUTO_COL; - colors[ImPlotCol_Fill] = IMPLOT_AUTO_COL; - colors[ImPlotCol_MarkerOutline] = IMPLOT_AUTO_COL; - colors[ImPlotCol_MarkerFill] = IMPLOT_AUTO_COL; - colors[ImPlotCol_ErrorBar] = ImVec4(0.90f, 0.90f, 0.90f, 1.00f); + colors[ImPlotCol_FrameBg] = ImVec4(0.43f, 0.43f, 0.43f, 0.39f); colors[ImPlotCol_PlotBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.35f); colors[ImPlotCol_PlotBorder] = ImVec4(0.50f, 0.50f, 0.50f, 0.50f); @@ -5807,11 +5776,6 @@ void StyleColorsDark(ImPlotStyle* dst) { style->MinorAlpha = 0.25f; - colors[ImPlotCol_Line] = IMPLOT_AUTO_COL; - colors[ImPlotCol_Fill] = IMPLOT_AUTO_COL; - colors[ImPlotCol_MarkerOutline] = IMPLOT_AUTO_COL; - colors[ImPlotCol_MarkerFill] = IMPLOT_AUTO_COL; - colors[ImPlotCol_ErrorBar] = IMPLOT_AUTO_COL; colors[ImPlotCol_FrameBg] = ImVec4(1.00f, 1.00f, 1.00f, 0.07f); colors[ImPlotCol_PlotBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.50f); colors[ImPlotCol_PlotBorder] = ImVec4(0.43f, 0.43f, 0.50f, 0.50f); @@ -5836,11 +5800,6 @@ void StyleColorsLight(ImPlotStyle* dst) { style->MinorAlpha = 1.0f; - colors[ImPlotCol_Line] = IMPLOT_AUTO_COL; - colors[ImPlotCol_Fill] = IMPLOT_AUTO_COL; - colors[ImPlotCol_MarkerOutline] = IMPLOT_AUTO_COL; - colors[ImPlotCol_MarkerFill] = IMPLOT_AUTO_COL; - colors[ImPlotCol_ErrorBar] = IMPLOT_AUTO_COL; colors[ImPlotCol_FrameBg] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f); colors[ImPlotCol_PlotBg] = ImVec4(0.42f, 0.57f, 1.00f, 0.13f); colors[ImPlotCol_PlotBorder] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); diff --git a/implot.h b/implot.h index 30543312..ae905a26 100644 --- a/implot.h +++ b/implot.h @@ -54,20 +54,21 @@ // Define attributes of all API symbols declarations (e.g. for DLL under Windows) // Using ImPlot via a shared library is not recommended, because we don't guarantee // backward nor forward ABI compatibility and also function call overhead. If you -// do use ImPlot as a DLL, be sure to call SetImGuiContext (see Miscellanous section). +// do use ImPlot as a DLL, be sure to call SetImGuiContext (see Miscellaneous section). #ifndef IMPLOT_API #define IMPLOT_API #endif // ImPlot version string. #define IMPLOT_VERSION "0.17" -// Indicates variable should deduced automatically. -#define IMPLOT_AUTO -1 -// Special color used to indicate that a color should be deduced automatically. -#define IMPLOT_AUTO_COL ImVec4(0,0,0,-1) // Macro for templated plotting functions; keeps header clean. #define IMPLOT_TMP template IMPLOT_API +// Indicates variable should deduced automatically. +constexpr int IMPLOT_AUTO = -1; +// Special color used to indicate that a color should be deduced automatically. +constexpr ImVec4 IMPLOT_AUTO_COL = ImVec4(0,0,0,-1); + //----------------------------------------------------------------------------- // [SECTION] Enums and Types //----------------------------------------------------------------------------- @@ -77,6 +78,7 @@ struct ImPlotContext; // ImPlot context (opaque struct, see implot_i // Enums/Flags typedef int ImAxis; // -> enum ImAxis_ +typedef int ImProp; // -> enum ImProp_ typedef int ImPlotFlags; // -> enum ImPlotFlags_ typedef int ImPlotAxisFlags; // -> enum ImPlotAxisFlags_ typedef int ImPlotSubplotFlags; // -> enum ImPlotSubplotFlags_ @@ -112,6 +114,7 @@ typedef int ImPlotColormap; // -> enum ImPlotColormap_ typedef int ImPlotLocation; // -> enum ImPlotLocation_ typedef int ImPlotBin; // -> enum ImPlotBin_ + // Axis indices. The values assigned may change; NEVER hardcode these. enum ImAxis_ { // horizontal axes @@ -122,14 +125,27 @@ enum ImAxis_ { ImAxis_Y1, // enabled by default ImAxis_Y2, // disabled by default ImAxis_Y3, // disabled by default - // bookeeping + // bookkeeping ImAxis_COUNT }; +// Plotting properties. These provide syntactic sugar for creating ImPlotSpecs from ImProp,value pairs. See ImPlotSpec documentation. +enum ImProp_ { + ImProp_LineColor, // line color (applies to lines, bar edges, marker edges); IMPLOT_AUTO_COL will use next Colormap color or current item color + ImProp_LineWeight, // line weight in pixels (applies to lines, bar edges, marker edges) + ImProp_FillColor, // fill color (applies to shaded regions, bar faces, marker faces); IMPLOT_AUTO_COL will use next Colormap color or current item color + ImProp_FillAlpha, // alpha multiplier (applies to FillColor) + ImProp_Marker, // marker type; specify ImPlotMarker_Auto to use the next unused marker + ImProp_Size, // size of markers (radius), error bar whiskers (width or height), and digital bars (height) *in pixels* + ImProp_Offset, // data index offset + ImProp_Stride, // data stride in bytes; IMPLOT_AUTO will result in sizeof(T) where T is the type passed to PlotX + ImProp_Flags // optional item flags; can be composed from common ImPlotItemFlags and/or specialized ImPlotXFlags +}; + // Options for plots (see BeginPlot). enum ImPlotFlags_ { ImPlotFlags_None = 0, // default - ImPlotFlags_NoTitle = 1 << 0, // the plot title will not be displayed (titles are also hidden if preceeded by double hashes, e.g. "##MyPlot") + ImPlotFlags_NoTitle = 1 << 0, // the plot title will not be displayed (titles are also hidden if preceded by double hashes, e.g. "##MyPlot") ImPlotFlags_NoLegend = 1 << 1, // the legend will not be displayed ImPlotFlags_NoMouseText = 1 << 2, // the mouse position, in plot coordinates, will not be displayed inside of the plot ImPlotFlags_NoInputs = 1 << 3, // the user will not be able to interact with the plot @@ -168,7 +184,7 @@ enum ImPlotAxisFlags_ { // Options for subplots (see BeginSubplot) enum ImPlotSubplotFlags_ { ImPlotSubplotFlags_None = 0, // default - ImPlotSubplotFlags_NoTitle = 1 << 0, // the subplot title will not be displayed (titles are also hidden if preceeded by double hashes, e.g. "##MySubplot") + ImPlotSubplotFlags_NoTitle = 1 << 0, // the subplot title will not be displayed (titles are also hidden if preceded by double hashes, e.g. "##MySubplot") ImPlotSubplotFlags_NoLegend = 1 << 1, // the legend will not be displayed (only applicable if ImPlotSubplotFlags_ShareItems is enabled) ImPlotSubplotFlags_NoMenus = 1 << 2, // the user will not be able to open context menus with right-click ImPlotSubplotFlags_NoResize = 1 << 3, // resize splitters between subplot cells will be not be provided @@ -218,14 +234,14 @@ enum ImPlotColormapScaleFlags_ { ImPlotColormapScaleFlags_Invert = 1 << 2, // invert the colormap bar and axis scale (this only affects rendering; if you only want to reverse the scale mapping, make scale_min > scale_max) }; -// Flags for ANY PlotX function +// Flags for ANY PlotX function. Used by setting ImPlotSpec::Flags. enum ImPlotItemFlags_ { ImPlotItemFlags_None = 0, ImPlotItemFlags_NoLegend = 1 << 0, // the item won't have a legend entry displayed ImPlotItemFlags_NoFit = 1 << 1, // the item won't be considered for plot fits }; -// Flags for PlotLine +// Flags for PlotLine. Used by setting ImPlotSpec::Flags. enum ImPlotLineFlags_ { ImPlotLineFlags_None = 0, // default ImPlotLineFlags_Segments = 1 << 10, // a line segment will be rendered from every two consecutive points @@ -235,95 +251,95 @@ enum ImPlotLineFlags_ { ImPlotLineFlags_Shaded = 1 << 14, // a filled region between the line and horizontal origin will be rendered; use PlotShaded for more advanced cases }; -// Flags for PlotScatter +// Flags for PlotScatter. Used by setting ImPlotSpec::Flags. enum ImPlotScatterFlags_ { ImPlotScatterFlags_None = 0, // default ImPlotScatterFlags_NoClip = 1 << 10, // markers on the edge of a plot will not be clipped }; -// Flags for PlotStairs +// Flags for PlotStairs. Used by setting ImPlotSpec::Flags. enum ImPlotStairsFlags_ { ImPlotStairsFlags_None = 0, // default ImPlotStairsFlags_PreStep = 1 << 10, // the y value is continued constantly to the left from every x position, i.e. the interval (x[i-1], x[i]] has the value y[i] ImPlotStairsFlags_Shaded = 1 << 11 // a filled region between the stairs and horizontal origin will be rendered; use PlotShaded for more advanced cases }; -// Flags for PlotShaded (placeholder) +// Flags for PlotShaded (placeholder). Used by setting ImPlotSpec::Flags. enum ImPlotShadedFlags_ { ImPlotShadedFlags_None = 0 // default }; -// Flags for PlotBars +// Flags for PlotBars. Used by setting ImPlotSpec::Flags. enum ImPlotBarsFlags_ { ImPlotBarsFlags_None = 0, // default ImPlotBarsFlags_Horizontal = 1 << 10, // bars will be rendered horizontally on the current y-axis }; -// Flags for PlotBarGroups +// Flags for PlotBarGroups. Used by setting ImPlotSpec::Flags. enum ImPlotBarGroupsFlags_ { ImPlotBarGroupsFlags_None = 0, // default ImPlotBarGroupsFlags_Horizontal = 1 << 10, // bar groups will be rendered horizontally on the current y-axis ImPlotBarGroupsFlags_Stacked = 1 << 11, // items in a group will be stacked on top of each other }; -// Flags for PlotErrorBars +// Flags for PlotErrorBars. Used by setting ImPlotSpec::Flags. enum ImPlotErrorBarsFlags_ { ImPlotErrorBarsFlags_None = 0, // default ImPlotErrorBarsFlags_Horizontal = 1 << 10, // error bars will be rendered horizontally on the current y-axis }; -// Flags for PlotStems +// Flags for PlotStems. Used by setting ImPlotSpec::Flags. enum ImPlotStemsFlags_ { ImPlotStemsFlags_None = 0, // default ImPlotStemsFlags_Horizontal = 1 << 10, // stems will be rendered horizontally on the current y-axis }; -// Flags for PlotInfLines +// Flags for PlotInfLines. Used by setting ImPlotSpec::Flags. enum ImPlotInfLinesFlags_ { ImPlotInfLinesFlags_None = 0, // default ImPlotInfLinesFlags_Horizontal = 1 << 10 // lines will be rendered horizontally on the current y-axis }; -// Flags for PlotPieChart +// Flags for PlotPieChart. Used by setting ImPlotSpec::Flags. enum ImPlotPieChartFlags_ { ImPlotPieChartFlags_None = 0, // default ImPlotPieChartFlags_Normalize = 1 << 10, // force normalization of pie chart values (i.e. always make a full circle if sum < 0) ImPlotPieChartFlags_IgnoreHidden = 1 << 11 // ignore hidden slices when drawing the pie chart (as if they were not there) }; -// Flags for PlotHeatmap +// Flags for PlotHeatmap. Used by setting ImPlotSpec::Flags. enum ImPlotHeatmapFlags_ { ImPlotHeatmapFlags_None = 0, // default ImPlotHeatmapFlags_ColMajor = 1 << 10, // data will be read in column major order }; -// Flags for PlotHistogram and PlotHistogram2D +// Flags for PlotHistogram and PlotHistogram2D. Used by setting ImPlotSpec::Flags. enum ImPlotHistogramFlags_ { ImPlotHistogramFlags_None = 0, // default ImPlotHistogramFlags_Horizontal = 1 << 10, // histogram bars will be rendered horizontally (not supported by PlotHistogram2D) ImPlotHistogramFlags_Cumulative = 1 << 11, // each bin will contain its count plus the counts of all previous bins (not supported by PlotHistogram2D) ImPlotHistogramFlags_Density = 1 << 12, // counts will be normalized, i.e. the PDF will be visualized, or the CDF will be visualized if Cumulative is also set - ImPlotHistogramFlags_NoOutliers = 1 << 13, // exclude values outside the specifed histogram range from the count toward normalizing and cumulative counts + ImPlotHistogramFlags_NoOutliers = 1 << 13, // exclude values outside the specified histogram range from the count toward normalizing and cumulative counts ImPlotHistogramFlags_ColMajor = 1 << 14 // data will be read in column major order (not supported by PlotHistogram) }; -// Flags for PlotDigital (placeholder) +// Flags for PlotDigital (placeholder). Used by setting ImPlotSpec::Flags. enum ImPlotDigitalFlags_ { ImPlotDigitalFlags_None = 0 // default }; -// Flags for PlotImage (placeholder) +// Flags for PlotImage (placeholder). Used by setting ImPlotSpec::Flags. enum ImPlotImageFlags_ { ImPlotImageFlags_None = 0 // default }; -// Flags for PlotText +// Flags for PlotText. Used by setting ImPlotSpec::Flags. enum ImPlotTextFlags_ { ImPlotTextFlags_None = 0, // default ImPlotTextFlags_Vertical = 1 << 10 // text will be rendered vertically }; -// Flags for PlotDummy (placeholder) +// Flags for PlotDummy (placeholder). Used by setting ImPlotSpec::Flags. enum ImPlotDummyFlags_ { ImPlotDummyFlags_None = 0 // default }; @@ -338,13 +354,6 @@ enum ImPlotCond_ // Plot styling colors. enum ImPlotCol_ { - // item styling colors - ImPlotCol_Line, // plot line/outline color (defaults to next unused color in current colormap) - ImPlotCol_Fill, // plot fill color for bars (defaults to the current line color) - ImPlotCol_MarkerOutline, // marker outline color (defaults to the current line color) - ImPlotCol_MarkerFill, // marker fill color (defaults to the current line color) - ImPlotCol_ErrorBar, // error bar color (defaults to ImGuiCol_Text) - // plot styling colors ImPlotCol_FrameBg, // plot frame background color (defaults to ImGuiCol_FrameBg) ImPlotCol_PlotBg, // plot area background color (defaults to ImGuiCol_WindowBg) ImPlotCol_PlotBorder, // plot area border color (defaults to ImGuiCol_Border) @@ -353,7 +362,7 @@ enum ImPlotCol_ { ImPlotCol_LegendText, // legend text color (defaults to ImPlotCol_InlayText) ImPlotCol_TitleText, // plot title text color (defaults to ImGuiCol_Text) ImPlotCol_InlayText, // color of text appearing inside of plots (defaults to ImGuiCol_Text) - ImPlotCol_AxisText, // axis label and tick lables color (defaults to ImGuiCol_Text) + ImPlotCol_AxisText, // axis label and tick labels color (defaults to ImGuiCol_Text) ImPlotCol_AxisGrid, // axis grid color (defaults to 25% ImPlotCol_AxisText) ImPlotCol_AxisTick, // axis tick color (defaults to AxisGrid) ImPlotCol_AxisBg, // background color of axis hover region (defaults to transparent) @@ -366,17 +375,8 @@ enum ImPlotCol_ { // Plot styling variables. enum ImPlotStyleVar_ { - // item styling variables - ImPlotStyleVar_LineWeight, // float, plot item line weight in pixels - ImPlotStyleVar_Marker, // int, marker specification - ImPlotStyleVar_MarkerSize, // float, marker size in pixels (roughly the marker's "radius") - ImPlotStyleVar_MarkerWeight, // float, plot outline weight of markers in pixels - ImPlotStyleVar_FillAlpha, // float, alpha modifier applied to all plot item fills - ImPlotStyleVar_ErrorBarSize, // float, error bar whisker width in pixels - ImPlotStyleVar_ErrorBarWeight, // float, error bar whisker weight in pixels - ImPlotStyleVar_DigitalBitHeight, // float, digital channels bit height (at 1) in pixels - ImPlotStyleVar_DigitalBitGap, // float, digital channels bit padding gap in pixels - // plot styling variables + ImPlotStyleVar_PlotDefaultSize, // ImVec2, default size used when ImVec2(0,0) is passed to BeginPlot + ImPlotStyleVar_PlotMinSize, // ImVec2, minimum size plot frame can be when shrunk ImPlotStyleVar_PlotBorderSize, // float, thickness of border around plot area ImPlotStyleVar_MinorAlpha, // float, alpha multiplier applied to minor axis grid lines ImPlotStyleVar_MajorTickLen, // ImVec2, major tick lengths for X and Y axes @@ -393,8 +393,8 @@ enum ImPlotStyleVar_ { ImPlotStyleVar_MousePosPadding, // ImVec2, padding between plot edge and interior info text ImPlotStyleVar_AnnotationPadding, // ImVec2, text padding around annotation labels ImPlotStyleVar_FitPadding, // ImVec2, additional fit padding as a percentage of the fit extents (e.g. ImVec2(0.1f,0.1f) adds 10% to the fit extents of X and Y) - ImPlotStyleVar_PlotDefaultSize, // ImVec2, default size used when ImVec2(0,0) is passed to BeginPlot - ImPlotStyleVar_PlotMinSize, // ImVec2, minimum size plot frame can be when shrunk + ImPlotStyleVar_DigitalPadding, // float, digital plot padding from bottom in pixels + ImPlotStyleVar_DigitalSpacing, // float, digital plot spacing gap in pixels ImPlotStyleVar_COUNT }; @@ -402,13 +402,14 @@ enum ImPlotStyleVar_ { enum ImPlotScale_ { ImPlotScale_Linear = 0, // default linear scale ImPlotScale_Time, // date/time scale - ImPlotScale_Log10, // base 10 logartithmic scale + ImPlotScale_Log10, // base 10 logarithmic scale ImPlotScale_SymLog, // symmetric log scale }; // Marker specifications. enum ImPlotMarker_ { - ImPlotMarker_None = -1, // no marker + ImPlotMarker_None = -2, // no marker + ImPlotMarker_Auto = -1, // automatic marker selection ImPlotMarker_Circle, // a circle marker (default) ImPlotMarker_Square, // a square maker ImPlotMarker_Diamond, // a diamond marker @@ -416,9 +417,9 @@ enum ImPlotMarker_ { ImPlotMarker_Down, // an downward-pointing triangle marker ImPlotMarker_Left, // an leftward-pointing triangle marker ImPlotMarker_Right, // an rightward-pointing triangle marker - ImPlotMarker_Cross, // a cross marker (not fillable) - ImPlotMarker_Plus, // a plus marker (not fillable) - ImPlotMarker_Asterisk, // a asterisk marker (not fillable) + ImPlotMarker_Cross, // a cross marker (not fill-able) + ImPlotMarker_Plus, // a plus marker (not fill-able) + ImPlotMarker_Asterisk, // a asterisk marker (not fill-able) ImPlotMarker_COUNT }; @@ -463,6 +464,83 @@ enum ImPlotBin_ { ImPlotBin_Scott = -4, // w = 3.49 * sigma / cbrt(n) }; +// Plot item styling specification. Provide these to PlotX functions to override styling, specify +// offsetting or stride, or set optional flags. This struct can be used in the following ways: +// +// 1. By declaring and defining a struct instance: +// +// ImPlotSpec spec; +// spec.LineColor = ImVec4(1,0,0,1); +// spec.LineWeight = 2.0f; +// spec.Marker = ImPlotMarker_Circle; +// spec.Flags = ImPlotItemFlags_NoLegend | ImPlotLineFlags_Segments; +// ImPlot::PlotLine("MyLine", xs, ys, 100, spec); +// +// 2. Inline using ImProp,value pairs (order does NOT matter): +// +// ImPlot::PlotLine("MyLine", xs, ys, 100, { +// ImProp_LineColor, ImVec4(1,0,0,1), +// ImProp_LineWeight, 2.0f, +// ImProp_Marker, ImPlotMarker_Circle, +// ImProp_Flags, ImPlotItemFlags_NoLegend | ImPlotLineFlags_Segments +// }); +struct ImPlotSpec { + ImVec4 LineColor = IMPLOT_AUTO_COL; // line color (applies to lines, bar edges, marker edges); IMPLOT_AUTO_COL will use next Colormap color or current item color + float LineWeight = 1.0f; // line weight in pixels (applies to lines, bar edges, marker edges) + ImVec4 FillColor = IMPLOT_AUTO_COL; // fill color (applies to shaded regions, bar faces, marker faces); IMPLOT_AUTO_COL will use next Colormap color or current item color + float FillAlpha = 1.0f; // alpha multiplier (applies to FillColor) + ImPlotMarker Marker = ImPlotMarker_None; // marker type; specify ImPlotMarker_Auto to use the next unused marker + float Size = 4; // size of markers (radius), error bar whiskers (width or height), and digital bars (height) *in pixels* + int Offset = 0; // data index offset + int Stride = IMPLOT_AUTO; // data stride in bytes; IMPLOT_AUTO will result in sizeof(T) where T is the type passed to PlotX + ImPlotItemFlags Flags = ImPlotItemFlags_None; // optional item flags; can be composed from common ImPlotItemFlags and/or specialized ImPlotXFlags + + ImPlotSpec() { } + + // Construct a plot item specification from ImProp,value pairs in any order, e.g. ImPlotSpec(ImProp_LineColor, my_color, ImProp_Marker, 4.0f) + template + ImPlotSpec(Args... args) { + static_assert((sizeof ...(Args)) % 2 == 0, "Odd number of arguments! You must provide ImProp,value pairs!"); + SetProp(args...); + } + + // Set properties from ImProp,value pairs in any order, e.g. SetProp(ImProp_LineColor, my_color, ImProp_Marker, 4.0f) + template + void SetProp(ImProp prop, Arg arg, Args... args) { + static_assert((sizeof ...(Args)) % 2 == 0, "Odd number of arguments! You must provide ImProp,value pairs!"); + SetProp(prop, arg); + SetProp(args...); + } + + // Set a property from a scalar value. + template + void SetProp(ImProp prop, T v) { + switch (prop) { + case ImProp_LineColor : LineColor = ImGui::ColorConvertU32ToFloat4((ImU32)v); return; + case ImProp_LineWeight : LineWeight = (float)v; return; + case ImProp_FillColor : FillColor = ImGui::ColorConvertU32ToFloat4((ImU32)v); return; + case ImProp_FillAlpha : FillAlpha = (float)v; return; + case ImProp_Marker : Marker = (ImPlotMarker)v; return; + case ImProp_Size : Size = (float)v; return; + case ImProp_Offset : Offset = (int)v; return; + case ImProp_Stride : Stride = (int)v; return; + case ImProp_Flags : Flags = (ImPlotItemFlags)v; return; + default: break; + } + IM_ASSERT(0 && "User provided an ImProp which cannot be set from scalar value!"); + } + + // Set a property from an ImVec4 value. + void SetProp(ImProp prop, const ImVec4& v) { + switch (prop) { + case ImProp_LineColor : LineColor = v; return; + case ImProp_FillColor : FillColor = v; return; + default: break; + } + IM_ASSERT(0 && "User provided an ImProp which cannot be set from ImVec4 value!"); + } +}; + // Double precision version of ImVec2 used by ImPlot. Extensible by end users. IM_MSVC_RUNTIME_CHECKS_OFF struct ImPlotPoint { @@ -497,25 +575,17 @@ struct ImPlotRect { bool Contains(const ImPlotPoint& p) const { return Contains(p.x, p.y); } bool Contains(double x, double y) const { return X.Contains(x) && Y.Contains(y); } ImPlotPoint Size() const { return ImPlotPoint(X.Size(), Y.Size()); } - ImPlotPoint Clamp(const ImPlotPoint& p) { return Clamp(p.x, p.y); } - ImPlotPoint Clamp(double x, double y) { return ImPlotPoint(X.Clamp(x),Y.Clamp(y)); } + ImPlotPoint Clamp(const ImPlotPoint& p) const { return Clamp(p.x, p.y); } + ImPlotPoint Clamp(double x, double y) const { return ImPlotPoint(X.Clamp(x),Y.Clamp(y)); } ImPlotPoint Min() const { return ImPlotPoint(X.Min, Y.Min); } ImPlotPoint Max() const { return ImPlotPoint(X.Max, Y.Max); } }; // Plot style structure struct ImPlotStyle { - // item styling variables - float LineWeight; // = 1, item line weight in pixels - int Marker; // = ImPlotMarker_None, marker specification - float MarkerSize; // = 4, marker size in pixels (roughly the marker's "radius") - float MarkerWeight; // = 1, outline weight of markers in pixels - float FillAlpha; // = 1, alpha modifier applied to plot fills - float ErrorBarSize; // = 5, error bar whisker width in pixels - float ErrorBarWeight; // = 1.5, error bar whisker weight in pixels - float DigitalBitHeight; // = 8, digital channels bit height (at y = 1.0f) in pixels - float DigitalBitGap; // = 4, digital channels bit padding gap in pixels - // plot styling variables + // plot styling + ImVec2 PlotDefaultSize; // = 400,300 default size used when ImVec2(0,0) is passed to BeginPlot + ImVec2 PlotMinSize; // = 200,150 minimum size plot frame can be when shrunk float PlotBorderSize; // = 1, line thickness of border around plot area float MinorAlpha; // = 0.25 alpha multiplier applied to minor axis grid lines ImVec2 MajorTickLen; // = 10,10 major tick lengths for X and Y axes @@ -524,6 +594,7 @@ struct ImPlotStyle { ImVec2 MinorTickSize; // = 1,1 line thickness of minor ticks ImVec2 MajorGridSize; // = 1,1 line thickness of major grid lines ImVec2 MinorGridSize; // = 1,1 line thickness of minor grid lines + // plot padding ImVec2 PlotPadding; // = 10,10 padding between widget frame and plot area, labels, or outside legends (i.e. main padding) ImVec2 LabelPadding; // = 5,5 padding between axes labels, tick labels, and plot edge ImVec2 LegendPadding; // = 10,10 legend padding from plot edges @@ -532,8 +603,8 @@ struct ImPlotStyle { ImVec2 MousePosPadding; // = 10,10 padding between plot edge and interior mouse location text ImVec2 AnnotationPadding; // = 2,2 text padding around annotation labels ImVec2 FitPadding; // = 0,0 additional fit padding as a percentage of the fit extents (e.g. ImVec2(0.1f,0.1f) adds 10% to the fit extents of X and Y) - ImVec2 PlotDefaultSize; // = 400,300 default size used when ImVec2(0,0) is passed to BeginPlot - ImVec2 PlotMinSize; // = 200,150 minimum size plot frame can be when shrunk + float DigitalPadding; // = 20, digital plot padding from bottom in pixels + float DigitalSpacing; // = 4, digital plot spacing gap in pixels // style colors ImVec4 Colors[ImPlotCol_COUNT]; // Array of styling colors. Indexable with ImPlotCol_ enums. // colormap @@ -696,7 +767,7 @@ IMPLOT_API bool BeginSubplots(const char* title_id, float* col_ratios = nullptr); // Only call EndSubplots() if BeginSubplots() returns true! Typically called at the end -// of an if statement conditioned on BeginSublots(). See example above. +// of an if statement conditioned on BeginSubplots(). See example above. IMPLOT_API void EndSubplots(); //----------------------------------------------------------------------------- @@ -734,7 +805,7 @@ IMPLOT_API void SetupAxis(ImAxis axis, const char* label=nullptr, ImPlotAxisFlag IMPLOT_API void SetupAxisLimits(ImAxis axis, double v_min, double v_max, ImPlotCond cond = ImPlotCond_Once); // Links an axis range limits to external values. Set to nullptr for no linkage. The pointer data must remain valid until EndPlot. IMPLOT_API void SetupAxisLinks(ImAxis axis, double* link_min, double* link_max); -// Sets the format of numeric axis labels via formater specifier (default="%g"). Formated values will be double (i.e. use %f). +// Sets the format of numeric axis labels via formatter specifier (default="%g"). Formatted values will be double (i.e. use %f). IMPLOT_API void SetupAxisFormat(ImAxis axis, const char* fmt); // Sets the format of numeric axis labels via formatter callback. Given #value, write a label into #buff. Optionally pass user data. IMPLOT_API void SetupAxisFormat(ImAxis axis, ImPlotFormatter formatter, void* data=nullptr); @@ -744,7 +815,7 @@ IMPLOT_API void SetupAxisTicks(ImAxis axis, const double* values, int n_ticks, c IMPLOT_API void SetupAxisTicks(ImAxis axis, double v_min, double v_max, int n_ticks, const char* const labels[]=nullptr, bool keep_default=false); // Sets an axis' scale using built-in options. IMPLOT_API void SetupAxisScale(ImAxis axis, ImPlotScale scale); -// Sets an axis' scale using user supplied forward and inverse transfroms. +// Sets an axis' scale using user supplied forward and inverse transforms. IMPLOT_API void SetupAxisScale(ImAxis axis, ImPlotTransform forward, ImPlotTransform inverse, void* data=nullptr); // Sets an axis' limits constraints. IMPLOT_API void SetupAxisLimitsConstraints(ImAxis axis, double v_min, double v_max); @@ -774,7 +845,7 @@ IMPLOT_API void SetupFinish(); // using a preceding button or slider widget to change the plot limits). In // this case, you can use the `SetNext` API below. While this is not as feature // rich as the Setup API, most common needs are provided. These functions can be -// called anwhere except for inside of `Begin/EndPlot`. For example: +// called anywhere except for inside of `Begin/EndPlot`. For example: // if (ImGui::Button("Center Plot")) // ImPlot::SetNextPlotLimits(-1,1,-1,1); @@ -804,7 +875,7 @@ IMPLOT_API void SetNextAxesToFit(); // [SECTION] Plot Items //----------------------------------------------------------------------------- -// The main plotting API is provied below. Call these functions between +// The main plotting API is provided below. Call these functions between // Begin/EndPlot and after any Setup API calls. Each plots data on the current // x and y axes, which can be changed with `SetAxis/Axes`. // @@ -817,13 +888,13 @@ IMPLOT_API void SetNextAxesToFit(); // // If you need to plot custom or non-homogenous data you have a few options: // -// 1. If your data is a simple struct/class (e.g. Vector2f), you can use striding. +// 1. If your data is a simple struct/class (e.g. Vector2f), you can use striding in your ImPlotSpec. // This is the most performant option if applicable. // // struct Vector2f { float X, Y; }; // ... // Vector2f data[42]; -// ImPlot::PlotLine("line", &data[0].x, &data[0].y, 42, 0, 0, sizeof(Vector2f)); +// ImPlot::PlotLine("line", &data[0].x, &data[0].y, 42, {ImProp_Stride, sizeof(Vector2f}); // // 2. Write a custom getter C function or C++ lambda and pass it and optionally your data to // an ImPlot function post-fixed with a G (e.g. PlotScatterG). This has a slight performance @@ -853,72 +924,72 @@ IMPLOT_API void SetNextAxesToFit(); // if you try plotting extremely large 64-bit integral types. Proceed with caution! // Plots a standard 2D line plot. -IMPLOT_TMP void PlotLine(const char* label_id, const T* values, int count, double xscale=1, double xstart=0, ImPlotLineFlags flags=0, int offset=0, int stride=sizeof(T)); -IMPLOT_TMP void PlotLine(const char* label_id, const T* xs, const T* ys, int count, ImPlotLineFlags flags=0, int offset=0, int stride=sizeof(T)); -IMPLOT_API void PlotLineG(const char* label_id, ImPlotGetter getter, void* data, int count, ImPlotLineFlags flags=0); +IMPLOT_TMP void PlotLine(const char* label_id, const T* values, int count, double xscale=1, double xstart=0, const ImPlotSpec& spec=ImPlotSpec()); +IMPLOT_TMP void PlotLine(const char* label_id, const T* xs, const T* ys, int count, const ImPlotSpec& spec=ImPlotSpec()); +IMPLOT_API void PlotLineG(const char* label_id, ImPlotGetter getter, void* data, int count, const ImPlotSpec& spec=ImPlotSpec()); // Plots a standard 2D scatter plot. Default marker is ImPlotMarker_Circle. -IMPLOT_TMP void PlotScatter(const char* label_id, const T* values, int count, double xscale=1, double xstart=0, ImPlotScatterFlags flags=0, int offset=0, int stride=sizeof(T)); -IMPLOT_TMP void PlotScatter(const char* label_id, const T* xs, const T* ys, int count, ImPlotScatterFlags flags=0, int offset=0, int stride=sizeof(T)); -IMPLOT_API void PlotScatterG(const char* label_id, ImPlotGetter getter, void* data, int count, ImPlotScatterFlags flags=0); +IMPLOT_TMP void PlotScatter(const char* label_id, const T* values, int count, double xscale=1, double xstart=0, const ImPlotSpec& spec=ImPlotSpec()); +IMPLOT_TMP void PlotScatter(const char* label_id, const T* xs, const T* ys, int count, const ImPlotSpec& spec=ImPlotSpec()); +IMPLOT_API void PlotScatterG(const char* label_id, ImPlotGetter getter, void* data, int count, const ImPlotSpec& spec=ImPlotSpec()); // Plots a a stairstep graph. The y value is continued constantly to the right from every x position, i.e. the interval [x[i], x[i+1]) has the value y[i] -IMPLOT_TMP void PlotStairs(const char* label_id, const T* values, int count, double xscale=1, double xstart=0, ImPlotStairsFlags flags=0, int offset=0, int stride=sizeof(T)); -IMPLOT_TMP void PlotStairs(const char* label_id, const T* xs, const T* ys, int count, ImPlotStairsFlags flags=0, int offset=0, int stride=sizeof(T)); -IMPLOT_API void PlotStairsG(const char* label_id, ImPlotGetter getter, void* data, int count, ImPlotStairsFlags flags=0); +IMPLOT_TMP void PlotStairs(const char* label_id, const T* values, int count, double xscale=1, double xstart=0, const ImPlotSpec& spec=ImPlotSpec()); +IMPLOT_TMP void PlotStairs(const char* label_id, const T* xs, const T* ys, int count, const ImPlotSpec& spec=ImPlotSpec()); +IMPLOT_API void PlotStairsG(const char* label_id, ImPlotGetter getter, void* data, int count, const ImPlotSpec& spec=ImPlotSpec()); // Plots a shaded (filled) region between two lines, or a line and a horizontal reference. Set yref to +/-INFINITY for infinite fill extents. -IMPLOT_TMP void PlotShaded(const char* label_id, const T* values, int count, double yref=0, double xscale=1, double xstart=0, ImPlotShadedFlags flags=0, int offset=0, int stride=sizeof(T)); -IMPLOT_TMP void PlotShaded(const char* label_id, const T* xs, const T* ys, int count, double yref=0, ImPlotShadedFlags flags=0, int offset=0, int stride=sizeof(T)); -IMPLOT_TMP void PlotShaded(const char* label_id, const T* xs, const T* ys1, const T* ys2, int count, ImPlotShadedFlags flags=0, int offset=0, int stride=sizeof(T)); -IMPLOT_API void PlotShadedG(const char* label_id, ImPlotGetter getter1, void* data1, ImPlotGetter getter2, void* data2, int count, ImPlotShadedFlags flags=0); +IMPLOT_TMP void PlotShaded(const char* label_id, const T* values, int count, double yref=0, double xscale=1, double xstart=0, const ImPlotSpec& spec=ImPlotSpec()); +IMPLOT_TMP void PlotShaded(const char* label_id, const T* xs, const T* ys, int count, double yref=0, const ImPlotSpec& spec=ImPlotSpec()); +IMPLOT_TMP void PlotShaded(const char* label_id, const T* xs, const T* ys1, const T* ys2, int count, const ImPlotSpec& spec=ImPlotSpec()); +IMPLOT_API void PlotShadedG(const char* label_id, ImPlotGetter getter1, void* data1, ImPlotGetter getter2, void* data2, int count, const ImPlotSpec& spec=ImPlotSpec()); // Plots a bar graph. Vertical by default. #bar_size and #shift are in plot units. -IMPLOT_TMP void PlotBars(const char* label_id, const T* values, int count, double bar_size=0.67, double shift=0, ImPlotBarsFlags flags=0, int offset=0, int stride=sizeof(T)); -IMPLOT_TMP void PlotBars(const char* label_id, const T* xs, const T* ys, int count, double bar_size, ImPlotBarsFlags flags=0, int offset=0, int stride=sizeof(T)); -IMPLOT_API void PlotBarsG(const char* label_id, ImPlotGetter getter, void* data, int count, double bar_size, ImPlotBarsFlags flags=0); +IMPLOT_TMP void PlotBars(const char* label_id, const T* values, int count, double bar_size=0.67, double shift=0, const ImPlotSpec& spec=ImPlotSpec()); +IMPLOT_TMP void PlotBars(const char* label_id, const T* xs, const T* ys, int count, double bar_size, const ImPlotSpec& spec=ImPlotSpec()); +IMPLOT_API void PlotBarsG(const char* label_id, ImPlotGetter getter, void* data, int count, double bar_size, const ImPlotSpec& spec=ImPlotSpec()); // Plots a group of bars. #values is a row-major matrix with #item_count rows and #group_count cols. #label_ids should have #item_count elements. -IMPLOT_TMP void PlotBarGroups(const char* const label_ids[], const T* values, int item_count, int group_count, double group_size=0.67, double shift=0, ImPlotBarGroupsFlags flags=0); +IMPLOT_TMP void PlotBarGroups(const char* const label_ids[], const T* values, int item_count, int group_count, double group_size=0.67, double shift=0, const ImPlotSpec& spec=ImPlotSpec()); // Plots vertical error bar. The label_id should be the same as the label_id of the associated line or bar plot. -IMPLOT_TMP void PlotErrorBars(const char* label_id, const T* xs, const T* ys, const T* err, int count, ImPlotErrorBarsFlags flags=0, int offset=0, int stride=sizeof(T)); -IMPLOT_TMP void PlotErrorBars(const char* label_id, const T* xs, const T* ys, const T* neg, const T* pos, int count, ImPlotErrorBarsFlags flags=0, int offset=0, int stride=sizeof(T)); +IMPLOT_TMP void PlotErrorBars(const char* label_id, const T* xs, const T* ys, const T* err, int count, const ImPlotSpec& spec=ImPlotSpec()); +IMPLOT_TMP void PlotErrorBars(const char* label_id, const T* xs, const T* ys, const T* neg, const T* pos, int count, const ImPlotSpec& spec=ImPlotSpec()); // Plots stems. Vertical by default. -IMPLOT_TMP void PlotStems(const char* label_id, const T* values, int count, double ref=0, double scale=1, double start=0, ImPlotStemsFlags flags=0, int offset=0, int stride=sizeof(T)); -IMPLOT_TMP void PlotStems(const char* label_id, const T* xs, const T* ys, int count, double ref=0, ImPlotStemsFlags flags=0, int offset=0, int stride=sizeof(T)); +IMPLOT_TMP void PlotStems(const char* label_id, const T* values, int count, double ref=0, double scale=1, double start=0, const ImPlotSpec& spec=ImPlotSpec()); +IMPLOT_TMP void PlotStems(const char* label_id, const T* xs, const T* ys, int count, double ref=0, const ImPlotSpec& spec=ImPlotSpec()); // Plots infinite vertical or horizontal lines (e.g. for references or asymptotes). -IMPLOT_TMP void PlotInfLines(const char* label_id, const T* values, int count, ImPlotInfLinesFlags flags=0, int offset=0, int stride=sizeof(T)); +IMPLOT_TMP void PlotInfLines(const char* label_id, const T* values, int count, const ImPlotSpec& spec=ImPlotSpec()); // Plots a pie chart. Center and radius are in plot units. #label_fmt can be set to nullptr for no labels. -IMPLOT_TMP void PlotPieChart(const char* const label_ids[], const T* values, int count, double x, double y, double radius, ImPlotFormatter fmt, void* fmt_data=nullptr, double angle0=90, ImPlotPieChartFlags flags=0); -IMPLOT_TMP void PlotPieChart(const char* const label_ids[], const T* values, int count, double x, double y, double radius, const char* label_fmt="%.1f", double angle0=90, ImPlotPieChartFlags flags=0); +IMPLOT_TMP void PlotPieChart(const char* const label_ids[], const T* values, int count, double x, double y, double radius, ImPlotFormatter fmt, void* fmt_data=nullptr, double angle0=90, const ImPlotSpec& spec=ImPlotSpec()); +IMPLOT_TMP void PlotPieChart(const char* const label_ids[], const T* values, int count, double x, double y, double radius, const char* label_fmt="%.1f", double angle0=90, const ImPlotSpec& spec=ImPlotSpec()); // Plots a 2D heatmap chart. Values are expected to be in row-major order by default. Leave #scale_min and scale_max both at 0 for automatic color scaling, or set them to a predefined range. #label_fmt can be set to nullptr for no labels. -IMPLOT_TMP void PlotHeatmap(const char* label_id, const T* values, int rows, int cols, double scale_min=0, double scale_max=0, const char* label_fmt="%.1f", const ImPlotPoint& bounds_min=ImPlotPoint(0,0), const ImPlotPoint& bounds_max=ImPlotPoint(1,1), ImPlotHeatmapFlags flags=0); +IMPLOT_TMP void PlotHeatmap(const char* label_id, const T* values, int rows, int cols, double scale_min=0, double scale_max=0, const char* label_fmt="%.1f", const ImPlotPoint& bounds_min=ImPlotPoint(0,0), const ImPlotPoint& bounds_max=ImPlotPoint(1,1), const ImPlotSpec& spec=ImPlotSpec()); // Plots a horizontal histogram. #bins can be a positive integer or an ImPlotBin_ method. If #range is left unspecified, the min/max of #values will be used as the range. // Otherwise, outlier values outside of the range are not binned. The largest bin count or density is returned. -IMPLOT_TMP double PlotHistogram(const char* label_id, const T* values, int count, int bins=ImPlotBin_Sturges, double bar_scale=1.0, ImPlotRange range=ImPlotRange(), ImPlotHistogramFlags flags=0); +IMPLOT_TMP double PlotHistogram(const char* label_id, const T* values, int count, int bins=ImPlotBin_Sturges, double bar_scale=1.0, ImPlotRange range=ImPlotRange(), const ImPlotSpec& spec=ImPlotSpec()); // Plots two dimensional, bivariate histogram as a heatmap. #x_bins and #y_bins can be a positive integer or an ImPlotBin. If #range is left unspecified, the min/max of // #xs an #ys will be used as the ranges. Otherwise, outlier values outside of range are not binned. The largest bin count or density is returned. -IMPLOT_TMP double PlotHistogram2D(const char* label_id, const T* xs, const T* ys, int count, int x_bins=ImPlotBin_Sturges, int y_bins=ImPlotBin_Sturges, ImPlotRect range=ImPlotRect(), ImPlotHistogramFlags flags=0); +IMPLOT_TMP double PlotHistogram2D(const char* label_id, const T* xs, const T* ys, int count, int x_bins=ImPlotBin_Sturges, int y_bins=ImPlotBin_Sturges, ImPlotRect range=ImPlotRect(), const ImPlotSpec& spec=ImPlotSpec()); // Plots digital data. Digital plots do not respond to y drag or zoom, and are always referenced to the bottom of the plot. -IMPLOT_TMP void PlotDigital(const char* label_id, const T* xs, const T* ys, int count, ImPlotDigitalFlags flags=0, int offset=0, int stride=sizeof(T)); -IMPLOT_API void PlotDigitalG(const char* label_id, ImPlotGetter getter, void* data, int count, ImPlotDigitalFlags flags=0); +IMPLOT_TMP void PlotDigital(const char* label_id, const T* xs, const T* ys, int count, const ImPlotSpec& spec=ImPlotSpec()); +IMPLOT_API void PlotDigitalG(const char* label_id, ImPlotGetter getter, void* data, int count, const ImPlotSpec& spec=ImPlotSpec()); // Plots an axis-aligned image. #bounds_min/bounds_max are in plot coordinates (y-up) and #uv0/uv1 are in texture coordinates (y-down). -IMPLOT_API void PlotImage(const char* label_id, ImTextureID user_texture_id, const ImPlotPoint& bounds_min, const ImPlotPoint& bounds_max, const ImVec2& uv0=ImVec2(0,0), const ImVec2& uv1=ImVec2(1,1), const ImVec4& tint_col=ImVec4(1,1,1,1), ImPlotImageFlags flags=0); +IMPLOT_API void PlotImage(const char* label_id, ImTextureID user_texture_id, const ImPlotPoint& bounds_min, const ImPlotPoint& bounds_max, const ImVec2& uv0=ImVec2(0,0), const ImVec2& uv1=ImVec2(1,1), const ImVec4& tint_col=ImVec4(1,1,1,1), const ImPlotSpec& spec=ImPlotSpec()); // Plots a centered text label at point x,y with an optional pixel offset. Text color can be changed with ImPlot::PushStyleColor(ImPlotCol_InlayText, ...). -IMPLOT_API void PlotText(const char* text, double x, double y, const ImVec2& pix_offset=ImVec2(0,0), ImPlotTextFlags flags=0); +IMPLOT_API void PlotText(const char* text, double x, double y, const ImVec2& pix_offset=ImVec2(0,0), const ImPlotSpec& spec=ImPlotSpec()); // Plots a dummy item (i.e. adds a legend entry colored by ImPlotCol_Line) -IMPLOT_API void PlotDummy(const char* label_id, ImPlotDummyFlags flags=0); +IMPLOT_API void PlotDummy(const char* label_id, const ImPlotSpec& spec=ImPlotSpec()); //----------------------------------------------------------------------------- // [SECTION] Plot Tools @@ -972,7 +1043,7 @@ IMPLOT_API ImVec2 PlotToPixels(double x, double y, ImAxis x_axis = IMPLOT_AUTO, // Get the current Plot position (top-left) in pixels. IMPLOT_API ImVec2 GetPlotPos(); -// Get the curent Plot size in pixels. +// Get the current Plot size in pixels. IMPLOT_API ImVec2 GetPlotSize(); // Returns the mouse position in x,y coordinates of the current plot. Passing IMPLOT_AUTO uses the current axes. @@ -1048,37 +1119,20 @@ IMPLOT_API void EndDragDropSource(); //----------------------------------------------------------------------------- // [SECTION] Styling //----------------------------------------------------------------------------- - + // Styling colors in ImPlot works similarly to styling colors in ImGui, but // with one important difference. Like ImGui, all style colors are stored in an // indexable array in ImPlotStyle. You can permanently modify these values through // GetStyle().Colors, or temporarily modify them with Push/Pop functions below. // However, by default all style colors in ImPlot default to a special color -// IMPLOT_AUTO_COL. The behavior of this color depends upon the style color to -// which it as applied: -// -// 1) For style colors associated with plot items (e.g. ImPlotCol_Line), -// IMPLOT_AUTO_COL tells ImPlot to color the item with the next unused -// color in the current colormap. Thus, every item will have a different -// color up to the number of colors in the colormap, at which point the -// colormap will roll over. For most use cases, you should not need to -// set these style colors to anything but IMPLOT_COL_AUTO; you are -// probably better off changing the current colormap. However, if you -// need to explicitly color a particular item you may either Push/Pop -// the style color around the item in question, or use the SetNextXXXStyle -// API below. If you permanently set one of these style colors to a specific -// color, or forget to call Pop, then all subsequent items will be styled -// with the color you set. -// -// 2) For style colors associated with plot styling (e.g. ImPlotCol_PlotBg), -// IMPLOT_AUTO_COL tells ImPlot to set that color from color data in your -// **ImGuiStyle**. The ImGuiCol_ that these style colors default to are -// detailed above, and in general have been mapped to produce plots visually -// consistent with your current ImGui style. Of course, you are free to -// manually set these colors to whatever you like, and further can Push/Pop -// them around individual plots for plot-specific styling (e.g. coloring axes). - -// Provides access to plot style structure for permanant modifications to colors, sizes, etc. +// IMPLOT_AUTO_COL. IMPLOT_AUTO_COL tells ImPlot to set that color from color data +// in your **ImGuiStyle**. The ImGuiCol_ that these style colors default to are +// detailed above, and in general have been mapped to produce plots visually +// consistent with your current ImGui style. Of course, you are free to +// manually set these colors to whatever you like, and further can Push/Pop +// them around individual plots for plot-specific styling (e.g. coloring axes). + +// Provides access to plot style structure for permanent modifications to colors, sizes, etc. IMPLOT_API ImPlotStyle& GetStyle(); // Style plot colors for current ImGui style (default). @@ -1108,21 +1162,7 @@ IMPLOT_API void PushStyleVar(ImPlotStyleVar idx, int val); IMPLOT_API void PushStyleVar(ImPlotStyleVar idx, const ImVec2& val); // Undo temporary style variable modification(s). Undo multiple pushes at once by increasing count. IMPLOT_API void PopStyleVar(int count = 1); - -// The following can be used to modify the style of the next plot item ONLY. They do -// NOT require calls to PopStyleX. Leave style attributes you don't want modified to -// IMPLOT_AUTO or IMPLOT_AUTO_COL. Automatic styles will be deduced from the current -// values in your ImPlotStyle or from Colormap data. - -// Set the line color and weight for the next item only. -IMPLOT_API void SetNextLineStyle(const ImVec4& col = IMPLOT_AUTO_COL, float weight = IMPLOT_AUTO); -// Set the fill color for the next item only. -IMPLOT_API void SetNextFillStyle(const ImVec4& col = IMPLOT_AUTO_COL, float alpha_mod = IMPLOT_AUTO); -// Set the marker style for the next item only. -IMPLOT_API void SetNextMarkerStyle(ImPlotMarker marker = IMPLOT_AUTO, float size = IMPLOT_AUTO, const ImVec4& fill = IMPLOT_AUTO_COL, float weight = IMPLOT_AUTO, const ImVec4& outline = IMPLOT_AUTO_COL); -// Set the error bar style for the next item only. -IMPLOT_API void SetNextErrorBarStyle(const ImVec4& col = IMPLOT_AUTO_COL, float size = IMPLOT_AUTO, float weight = IMPLOT_AUTO); - + // Gets the last item primary color (i.e. its legend icon color) IMPLOT_API ImVec4 GetLastItemColor(); @@ -1130,7 +1170,10 @@ IMPLOT_API ImVec4 GetLastItemColor(); IMPLOT_API const char* GetStyleColorName(ImPlotCol idx); // Returns the null terminated string name for an ImPlotMarker. IMPLOT_API const char* GetMarkerName(ImPlotMarker idx); - + +// Returns the next marker and advances the marker for the current plot. You need to call this between Begin/EndPlot! +IMPLOT_API ImPlotMarker NextMarker(); + //----------------------------------------------------------------------------- // [SECTION] Colormaps //----------------------------------------------------------------------------- @@ -1185,7 +1228,7 @@ IMPLOT_API ImVec4 SampleColormap(float t, ImPlotColormap cmap = IMPLOT_AUTO); IMPLOT_API void ColormapScale(const char* label, double scale_min, double scale_max, const ImVec2& size = ImVec2(0,0), const char* format = "%g", ImPlotColormapScaleFlags flags = 0, ImPlotColormap cmap = IMPLOT_AUTO); // Shows a horizontal slider with a colormap gradient background. Optionally returns the color sampled at t in [0 1]. IMPLOT_API bool ColormapSlider(const char* label, float* t, ImVec4* out = nullptr, const char* format = "", ImPlotColormap cmap = IMPLOT_AUTO); -// Shows a button with a colormap gradient brackground. +// Shows a button with a colormap gradient background. IMPLOT_API bool ColormapButton(const char* label, const ImVec2& size = ImVec2(0,0), ImPlotColormap cmap = IMPLOT_AUTO); // When items in a plot sample their color from a colormap, the color is cached and does not change @@ -1200,8 +1243,8 @@ IMPLOT_API void BustColorCache(const char* plot_title_id = nullptr); //----------------------------------------------------------------------------- // [SECTION] Input Mapping //----------------------------------------------------------------------------- - -// Provides access to input mapping structure for permanant modifications to controls for pan, select, etc. + +// Provides access to input mapping structure for permanent modifications to controls for pan, select, etc. IMPLOT_API ImPlotInputMap& GetInputMap(); // Default input mapping: pan = LMB drag, box select = RMB drag, fit = LMB double click, context menu = RMB click, zoom = scroll. diff --git a/implot_demo.cpp b/implot_demo.cpp index 79064fdf..88dd6110 100644 --- a/implot_demo.cpp +++ b/implot_demo.cpp @@ -298,8 +298,10 @@ void Demo_LinePlots() { if (ImPlot::BeginPlot("Line Plots")) { ImPlot::SetupAxes("x","y"); ImPlot::PlotLine("f(x)", xs1, ys1, 1001); - ImPlot::SetNextMarkerStyle(ImPlotMarker_Circle); - ImPlot::PlotLine("g(x)", xs2, ys2, 20,ImPlotLineFlags_Segments); + ImPlot::PlotLine("g(x)", xs2, ys2, 20,{ + ImProp_Marker, ImPlotMarker_Circle, + ImProp_Flags, ImPlotLineFlags_Segments + }); ImPlot::EndPlot(); } } @@ -343,11 +345,12 @@ void Demo_FilledLinePlots() { ImPlot::SetupAxes("Days","Price"); ImPlot::SetupAxesLimits(0,100,0,500); if (show_fills) { - ImPlot::PushStyleVar(ImPlotStyleVar_FillAlpha, 0.25f); - ImPlot::PlotShaded("Stock 1", xs1, ys1, 101, shade_mode == 0 ? -INFINITY : shade_mode == 1 ? INFINITY : fill_ref, flags); - ImPlot::PlotShaded("Stock 2", xs1, ys2, 101, shade_mode == 0 ? -INFINITY : shade_mode == 1 ? INFINITY : fill_ref, flags); - ImPlot::PlotShaded("Stock 3", xs1, ys3, 101, shade_mode == 0 ? -INFINITY : shade_mode == 1 ? INFINITY : fill_ref, flags); - ImPlot::PopStyleVar(); + ImPlotSpec spec; + spec.Flags = flags; + spec.FillAlpha = 0.25f; + ImPlot::PlotShaded("Stock 1", xs1, ys1, 101, shade_mode == 0 ? -INFINITY : shade_mode == 1 ? INFINITY : fill_ref, spec); + ImPlot::PlotShaded("Stock 2", xs1, ys2, 101, shade_mode == 0 ? -INFINITY : shade_mode == 1 ? INFINITY : fill_ref, spec); + ImPlot::PlotShaded("Stock 3", xs1, ys3, 101, shade_mode == 0 ? -INFINITY : shade_mode == 1 ? INFINITY : fill_ref, spec); } if (show_lines) { ImPlot::PlotLine("Stock 1", xs1, ys1, 101); @@ -371,17 +374,15 @@ void Demo_ShadedPlots() { ys3[i] = 0.75f + 0.2f * sinf(25 * xs[i]); ys4[i] = 0.75f + 0.1f * cosf(25 * xs[i]); } - static float alpha = 0.25f; - ImGui::DragFloat("Alpha",&alpha,0.01f,0,1); + static ImPlotSpec spec(ImProp_FillAlpha, 0.25f); + ImGui::DragFloat("Alpha",&spec.FillAlpha,0.01f,0,1); if (ImPlot::BeginPlot("Shaded Plots")) { - ImPlot::PushStyleVar(ImPlotStyleVar_FillAlpha, alpha); - ImPlot::PlotShaded("Uncertain Data",xs,ys1,ys2,1001); - ImPlot::PlotLine("Uncertain Data", xs, ys, 1001); - ImPlot::PlotShaded("Overlapping",xs,ys3,ys4,1001); - ImPlot::PlotLine("Overlapping",xs,ys3,1001); - ImPlot::PlotLine("Overlapping",xs,ys4,1001); - ImPlot::PopStyleVar(); + ImPlot::PlotShaded("Uncertain Data",xs,ys1,ys2,1001, spec); + ImPlot::PlotLine("Uncertain Data", xs, ys, 1001, spec); + ImPlot::PlotShaded("Overlapping",xs,ys3,ys4,1001, spec); + ImPlot::PlotLine("Overlapping",xs,ys3,1001, spec); + ImPlot::PlotLine("Overlapping",xs,ys4,1001, spec); ImPlot::EndPlot(); } } @@ -403,10 +404,13 @@ void Demo_ScatterPlots() { if (ImPlot::BeginPlot("Scatter Plot")) { ImPlot::PlotScatter("Data 1", xs1, ys1, 100); - ImPlot::PushStyleVar(ImPlotStyleVar_FillAlpha, 0.25f); - ImPlot::SetNextMarkerStyle(ImPlotMarker_Square, 6, ImPlot::GetColormapColor(1), IMPLOT_AUTO, ImPlot::GetColormapColor(1)); - ImPlot::PlotScatter("Data 2", xs2, ys2, 50); - ImPlot::PopStyleVar(); + ImPlot::PlotScatter("Data 2", xs2, ys2, 50, { + ImProp_Marker, ImPlotMarker_Square, + ImProp_Size, 6, + ImProp_LineColor, GetColormapColor(1), + ImProp_FillColor, GetColormapColor(1), + ImProp_FillAlpha, 0.25f + }); ImPlot::EndPlot(); } } @@ -424,18 +428,19 @@ void Demo_StairstepPlots() { if (ImPlot::BeginPlot("Stairstep Plot")) { ImPlot::SetupAxes("x","f(x)"); ImPlot::SetupAxesLimits(0,1,0,1); - - ImPlot::PushStyleColor(ImPlotCol_Line, ImVec4(0.5f,0.5f,0.5f,1.0f)); - ImPlot::PlotLine("##1",ys1,21,0.05f); - ImPlot::PlotLine("##2",ys2,21,0.05f); - ImPlot::PopStyleColor(); - - ImPlot::SetNextMarkerStyle(ImPlotMarker_Circle); - ImPlot::SetNextFillStyle(IMPLOT_AUTO_COL, 0.25f); - ImPlot::PlotStairs("Post Step (default)", ys1, 21, 0.05f, 0, flags); - ImPlot::SetNextMarkerStyle(ImPlotMarker_Circle); - ImPlot::SetNextFillStyle(IMPLOT_AUTO_COL, 0.25f); - ImPlot::PlotStairs("Pre Step", ys2, 21, 0.05f, 0, flags|ImPlotStairsFlags_PreStep); + ImPlot::PlotLine("##1",ys1,21,0.05f, 0, {ImProp_LineColor, ImVec4(0.5f,0.5f,0.5f,1.0f)}); + ImPlot::PlotLine("##2",ys2,21,0.05f, 0, {ImProp_LineColor, ImVec4(0.5f,0.5f,0.5f,1.0f)}); + + ImPlotSpec spec; + spec.Flags = flags; + spec.FillAlpha = 0.25f; + spec.Marker = ImPlotMarker_Auto; + ImPlot::PlotStairs("Post Step (default)", ys1, 21, 0.05f, 0, spec); + + spec.Flags = flags|ImPlotStairsFlags_PreStep; + spec.FillAlpha = 0.25f; + spec.Marker = ImPlotMarker_Auto; + ImPlot::PlotStairs("Pre Step", ys2, 21, 0.05f, 0, spec); ImPlot::EndPlot(); } @@ -447,7 +452,7 @@ void Demo_BarPlots() { static ImS8 data[10] = {1,2,3,4,5,6,7,8,9,10}; if (ImPlot::BeginPlot("Bar Plot")) { ImPlot::PlotBars("Vertical",data,10,0.7,1); - ImPlot::PlotBars("Horizontal",data,10,0.4,1,ImPlotBarsFlags_Horizontal); + ImPlot::PlotBars("Horizontal",data,10,0.4,1,{ImProp_Flags, ImPlotBarsFlags_Horizontal}); ImPlot::EndPlot(); } } @@ -482,12 +487,12 @@ void Demo_BarGroups() { if (horz) { ImPlot::SetupAxes("Score","Student",ImPlotAxisFlags_AutoFit,ImPlotAxisFlags_AutoFit); ImPlot::SetupAxisTicks(ImAxis_Y1,positions, groups, glabels); - ImPlot::PlotBarGroups(ilabels,data,items,groups,size,0,flags|ImPlotBarGroupsFlags_Horizontal); + ImPlot::PlotBarGroups(ilabels,data,items,groups,size,0,{ImProp_Flags, flags|ImPlotBarGroupsFlags_Horizontal}); } else { ImPlot::SetupAxes("Student","Score",ImPlotAxisFlags_AutoFit,ImPlotAxisFlags_AutoFit); ImPlot::SetupAxisTicks(ImAxis_X1,positions, groups, glabels); - ImPlot::PlotBarGroups(ilabels,data,items,groups,size,0,flags); + ImPlot::PlotBarGroups(ilabels,data,items,groups,size,0,{ImProp_Flags, flags}); } ImPlot::EndPlot(); } @@ -532,10 +537,11 @@ void Demo_BarStacks() { ImPlot::SetupLegend(ImPlotLocation_South, ImPlotLegendFlags_Outside|ImPlotLegendFlags_Horizontal); ImPlot::SetupAxes(nullptr,nullptr,ImPlotAxisFlags_AutoFit|ImPlotAxisFlags_NoDecorations,ImPlotAxisFlags_AutoFit|ImPlotAxisFlags_Invert); ImPlot::SetupAxisTicks(ImAxis_Y1,0,19,20,politicians,false); + ImPlotSpec spec; spec.Flags = ImPlotBarGroupsFlags_Stacked|ImPlotBarGroupsFlags_Horizontal; if (diverging) - ImPlot::PlotBarGroups(labels_div,data_div,9,20,0.75,0,ImPlotBarGroupsFlags_Stacked|ImPlotBarGroupsFlags_Horizontal); + ImPlot::PlotBarGroups(labels_div,data_div,9,20,0.75,0,spec); else - ImPlot::PlotBarGroups(labels_reg,data_reg,6,20,0.75,0,ImPlotBarGroupsFlags_Stacked|ImPlotBarGroupsFlags_Horizontal); + ImPlot::PlotBarGroups(labels_reg,data_reg,6,20,0.75,0,spec); ImPlot::EndPlot(); } ImPlot::PopColormap(); @@ -556,17 +562,22 @@ void Demo_ErrorBars() { if (ImPlot::BeginPlot("##ErrorBars")) { ImPlot::SetupAxesLimits(0, 6, 0, 10); + ImPlot::PlotBars("Bar", xs, bar, 5, 0.5f); ImPlot::PlotErrorBars("Bar", xs, bar, err1, 5); - ImPlot::SetNextErrorBarStyle(ImPlot::GetColormapColor(1), 0); - ImPlot::PlotErrorBars("Line", xs, lin1, err1, err2, 5); - ImPlot::SetNextMarkerStyle(ImPlotMarker_Square); - ImPlot::PlotLine("Line", xs, lin1, 5); - ImPlot::PushStyleColor(ImPlotCol_ErrorBar, ImPlot::GetColormapColor(2)); - ImPlot::PlotErrorBars("Scatter", xs, lin2, err2, 5); - ImPlot::PlotErrorBars("Scatter", xs, lin2, err3, err4, 5, ImPlotErrorBarsFlags_Horizontal); - ImPlot::PopStyleColor(); - ImPlot::PlotScatter("Scatter", xs, lin2, 5); + + ImPlot::PlotErrorBars("Line", xs, lin1, err1, err2, 5, {ImProp_LineColor, GetColormapColor(1), ImProp_Size, 0}); + ImPlot::PlotLine("Line", xs, lin1, 5, {ImProp_Marker, ImPlotMarker_Square}); + + ImPlotSpec spec; + spec.LineColor = GetColormapColor(2); + spec.Size = 6; + spec.LineWeight = 1.5f; + ImPlot::PlotErrorBars("Scatter", xs, lin2, err2, 5, spec); + spec.Flags = ImPlotErrorBarsFlags_Horizontal; + ImPlot::PlotErrorBars("Scatter", xs, lin2, err3, err4, 5, spec); + ImPlot::PlotScatter("Scatter", xs, lin2, 5); + ImPlot::EndPlot(); } } @@ -584,8 +595,7 @@ void Demo_StemPlots() { ImPlot::SetupAxisLimits(ImAxis_X1,0,1.0); ImPlot::SetupAxisLimits(ImAxis_Y1,0,1.6); ImPlot::PlotStems("Stems 1",xs,ys1,51); - ImPlot::SetNextMarkerStyle(ImPlotMarker_Circle); - ImPlot::PlotStems("Stems 2", xs, ys2,51); + ImPlot::PlotStems("Stems 2", xs, ys2,51, 0, {ImProp_Marker, ImPlotMarker_Circle}); ImPlot::EndPlot(); } } @@ -597,7 +607,7 @@ void Demo_InfiniteLines() { if (ImPlot::BeginPlot("##Infinite")) { ImPlot::SetupAxes(nullptr,nullptr,ImPlotAxisFlags_NoInitialFit,ImPlotAxisFlags_NoInitialFit); ImPlot::PlotInfLines("Vertical",vals,3); - ImPlot::PlotInfLines("Horizontal",vals,3,ImPlotInfLinesFlags_Horizontal); + ImPlot::PlotInfLines("Horizontal",vals,3,{ImProp_Flags, ImPlotInfLinesFlags_Horizontal}); ImPlot::EndPlot(); } } @@ -616,7 +626,7 @@ void Demo_PieCharts() { if (ImPlot::BeginPlot("##Pie1", ImVec2(250,250), ImPlotFlags_Equal | ImPlotFlags_NoMouseText)) { ImPlot::SetupAxes(nullptr, nullptr, ImPlotAxisFlags_NoDecorations, ImPlotAxisFlags_NoDecorations); ImPlot::SetupAxesLimits(0, 1, 0, 1); - ImPlot::PlotPieChart(labels1, data1, 4, 0.5, 0.5, 0.4, "%.2f", 90, flags); + ImPlot::PlotPieChart(labels1, data1, 4, 0.5, 0.5, 0.4, "%.2f", 90, {ImProp_Flags, flags}); ImPlot::EndPlot(); } @@ -629,7 +639,7 @@ void Demo_PieCharts() { if (ImPlot::BeginPlot("##Pie2", ImVec2(250,250), ImPlotFlags_Equal | ImPlotFlags_NoMouseText)) { ImPlot::SetupAxes(nullptr, nullptr, ImPlotAxisFlags_NoDecorations, ImPlotAxisFlags_NoDecorations); ImPlot::SetupAxesLimits(0, 1, 0, 1); - ImPlot::PlotPieChart(labels2, data2, 5, 0.5, 0.5, 0.4, "%.0f", 180, flags); + ImPlot::PlotPieChart(labels2, data2, 5, 0.5, 0.5, 0.4, "%.0f", 180, {ImProp_Flags, flags}); ImPlot::EndPlot(); } ImPlot::PopColormap(); @@ -677,7 +687,7 @@ void Demo_Heatmaps() { ImPlot::SetupAxes(nullptr, nullptr, axes_flags, axes_flags); ImPlot::SetupAxisTicks(ImAxis_X1,0 + 1.0/14.0, 1 - 1.0/14.0, 7, xlabels); ImPlot::SetupAxisTicks(ImAxis_Y1,1 - 1.0/14.0, 0 + 1.0/14.0, 7, ylabels); - ImPlot::PlotHeatmap("heat",values1[0],7,7,scale_min,scale_max,"%g",ImPlotPoint(0,0),ImPlotPoint(1,1),hm_flags); + ImPlot::PlotHeatmap("heat",values1[0],7,7,scale_min,scale_max,"%g",ImPlotPoint(0,0),ImPlotPoint(1,1), {ImProp_Flags, hm_flags}); ImPlot::EndPlot(); } ImGui::SameLine(); @@ -755,8 +765,10 @@ void Demo_Histogram() { if (ImPlot::BeginPlot("##Histograms")) { ImPlot::SetupAxes(nullptr,nullptr,ImPlotAxisFlags_AutoFit,ImPlotAxisFlags_AutoFit); - ImPlot::SetNextFillStyle(IMPLOT_AUTO_COL,0.5f); - ImPlot::PlotHistogram("Empirical", dist.Data, 10000, bins, 1.0, range ? ImPlotRange(rmin,rmax) : ImPlotRange(), hist_flags); + ImPlot::PlotHistogram("Empirical", dist.Data, 10000, bins, 1.0, range ? ImPlotRange(rmin,rmax) : ImPlotRange(), { + ImProp_FillAlpha, 0.5f, + ImProp_Flags, hist_flags + }); if ((hist_flags & ImPlotHistogramFlags_Density) && !(hist_flags & ImPlotHistogramFlags_NoOutliers)) { if (hist_flags & ImPlotHistogramFlags_Horizontal) ImPlot::PlotLine("Theoretical",y,x,100); @@ -788,7 +800,7 @@ void Demo_Histogram2D() { if (ImPlot::BeginPlot("##Hist2D",ImVec2(ImGui::GetContentRegionAvail().x-100-ImGui::GetStyle().ItemSpacing.x,0))) { ImPlot::SetupAxes(nullptr, nullptr, flags, flags); ImPlot::SetupAxesLimits(-6,6,-6,6); - max_count = ImPlot::PlotHistogram2D("Hist2D",dist1.Data,dist2.Data,count,xybins[0],xybins[1],ImPlotRect(-6,6,-6,6), hist_flags); + max_count = ImPlot::PlotHistogram2D("Hist2D",dist1.Data,dist2.Data,count,xybins[0],xybins[1],ImPlotRect(-6,6,-6,6), {ImProp_Flags, hist_flags}); ImPlot::EndPlot(); } ImGui::SameLine(); @@ -805,14 +817,16 @@ void Demo_DigitalPlots() { ImGui::Unindent(); static bool paused = false; - static ScrollingBuffer dataDigital[2]; + static ScrollingBuffer dataDigital[3]; static ScrollingBuffer dataAnalog[2]; - static bool showDigital[2] = {true, false}; + static bool showDigital[3] = {true, false, false}; static bool showAnalog[2] = {true, false}; char label[32]; + ImGui::Checkbox("Pause", &paused); ImGui::Checkbox("digital_0", &showDigital[0]); ImGui::SameLine(); ImGui::Checkbox("digital_1", &showDigital[1]); ImGui::SameLine(); + ImGui::Checkbox("digital_2", &showDigital[2]); ImGui::SameLine(); ImGui::Checkbox("analog_0", &showAnalog[0]); ImGui::SameLine(); ImGui::Checkbox("analog_1", &showAnalog[1]); @@ -824,6 +838,8 @@ void Demo_DigitalPlots() { dataDigital[0].AddPoint(t, sinf(2*t) > 0.45); if (showDigital[1]) dataDigital[1].AddPoint(t, sinf(2*t) < 0.45); + if (showDigital[2]) + dataDigital[2].AddPoint(t, sinf(50*t) > 0.5); //Analog signal values if (showAnalog[0]) dataAnalog[0].AddPoint(t, sinf(2*t)); @@ -833,17 +849,25 @@ void Demo_DigitalPlots() { if (ImPlot::BeginPlot("##Digital")) { ImPlot::SetupAxisLimits(ImAxis_X1, t - 10.0, t, paused ? ImGuiCond_Once : ImGuiCond_Always); ImPlot::SetupAxisLimits(ImAxis_Y1, -1, 1); - for (int i = 0; i < 2; ++i) { + for (int i = 0; i < 3; ++i) { if (showDigital[i] && dataDigital[i].Data.size() > 0) { snprintf(label, sizeof(label), "digital_%d", i); - ImPlot::PlotDigital(label, &dataDigital[i].Data[0].x, &dataDigital[i].Data[0].y, dataDigital[i].Data.size(), 0, dataDigital[i].Offset, 2 * sizeof(float)); + ImPlot::PlotDigital(label, &dataDigital[i].Data[0].x, &dataDigital[i].Data[0].y, dataDigital[i].Data.size(), { + ImProp_Offset, dataDigital[i].Offset, + ImProp_Stride, 2 * sizeof(float), + ImProp_Size, (i+1) * 4 + }); } } for (int i = 0; i < 2; ++i) { if (showAnalog[i]) { snprintf(label, sizeof(label), "analog_%d", i); - if (dataAnalog[i].Data.size() > 0) - ImPlot::PlotLine(label, &dataAnalog[i].Data[0].x, &dataAnalog[i].Data[0].y, dataAnalog[i].Data.size(), 0, dataAnalog[i].Offset, 2 * sizeof(float)); + if (dataAnalog[i].Data.size() > 0) { + ImPlot::PlotLine(label, &dataAnalog[i].Data[0].x, &dataAnalog[i].Data[0].y, dataAnalog[i].Data.size(), { + ImProp_Offset, dataAnalog[i].Offset, + ImProp_Stride, 2 * sizeof(float) + }); + } } } ImPlot::EndPlot(); @@ -898,17 +922,25 @@ void Demo_RealtimePlots() { ImPlot::SetupAxes(nullptr, nullptr, flags, flags); ImPlot::SetupAxisLimits(ImAxis_X1,t - history, t, ImGuiCond_Always); ImPlot::SetupAxisLimits(ImAxis_Y1,0,1); - ImPlot::SetNextFillStyle(IMPLOT_AUTO_COL,0.5f); - ImPlot::PlotShaded("Mouse X", &sdata1.Data[0].x, &sdata1.Data[0].y, sdata1.Data.size(), -INFINITY, 0, sdata1.Offset, 2 * sizeof(float)); - ImPlot::PlotLine("Mouse Y", &sdata2.Data[0].x, &sdata2.Data[0].y, sdata2.Data.size(), 0, sdata2.Offset, 2*sizeof(float)); + ImPlotSpec spec; + spec.Offset = sdata1.Offset; + spec.Stride = 2 * sizeof(float); + spec.FillAlpha = 0.5f; + ImPlot::PlotShaded("Mouse X", &sdata1.Data[0].x, &sdata1.Data[0].y, sdata1.Data.size(), -INFINITY, spec); + spec.Offset = sdata2.Offset; + spec.Stride = 2 * sizeof(float); + ImPlot::PlotLine("Mouse Y", &sdata2.Data[0].x, &sdata2.Data[0].y, sdata2.Data.size(), spec); ImPlot::EndPlot(); } if (ImPlot::BeginPlot("##Rolling", ImVec2(-1,150))) { ImPlot::SetupAxes(nullptr, nullptr, flags, flags); ImPlot::SetupAxisLimits(ImAxis_X1,0,history, ImGuiCond_Always); ImPlot::SetupAxisLimits(ImAxis_Y1,0,1); - ImPlot::PlotLine("Mouse X", &rdata1.Data[0].x, &rdata1.Data[0].y, rdata1.Data.size(), 0, 0, 2 * sizeof(float)); - ImPlot::PlotLine("Mouse Y", &rdata2.Data[0].x, &rdata2.Data[0].y, rdata2.Data.size(), 0, 0, 2 * sizeof(float)); + ImPlotSpec spec; + spec.Offset = 0; + spec.Stride = 2 * sizeof(float); + ImPlot::PlotLine("Mouse X", &rdata1.Data[0].x, &rdata1.Data[0].y, rdata1.Data.size(), spec); + ImPlot::PlotLine("Mouse Y", &rdata2.Data[0].x, &rdata2.Data[0].y, rdata2.Data.size(), spec); ImPlot::EndPlot(); } } @@ -916,10 +948,9 @@ void Demo_RealtimePlots() { //----------------------------------------------------------------------------- void Demo_MarkersAndText() { - static float mk_size = ImPlot::GetStyle().MarkerSize; - static float mk_weight = ImPlot::GetStyle().MarkerWeight; - ImGui::DragFloat("Marker Size",&mk_size,0.1f,2.0f,10.0f,"%.2f px"); - ImGui::DragFloat("Marker Weight", &mk_weight,0.05f,0.5f,3.0f,"%.2f px"); + static ImPlotSpec spec(ImProp_Marker, ImPlotMarker_Auto); + ImGui::DragFloat("Marker Size",&spec.Size,0.1f,2.0f,10.0f,"%.2f px"); + ImGui::DragFloat("Marker Weight", &spec.LineWeight,0.05f,0.5f,3.0f,"%.2f px"); if (ImPlot::BeginPlot("##MarkerStyles", ImVec2(-1,0), ImPlotFlags_CanvasOnly)) { @@ -932,8 +963,8 @@ void Demo_MarkersAndText() { // filled markers for (int m = 0; m < ImPlotMarker_COUNT; ++m) { ImGui::PushID(m); - ImPlot::SetNextMarkerStyle(m, mk_size, IMPLOT_AUTO_COL, mk_weight); - ImPlot::PlotLine("##Filled", xs, ys, 2); + spec.FillAlpha = 1.0f; + ImPlot::PlotLine("##Filled", xs, ys, 2, spec); ImGui::PopID(); ys[0]--; ys[1]--; } @@ -941,8 +972,8 @@ void Demo_MarkersAndText() { // open markers for (int m = 0; m < ImPlotMarker_COUNT; ++m) { ImGui::PushID(m); - ImPlot::SetNextMarkerStyle(m, mk_size, ImVec4(0,0,0,0), mk_weight); - ImPlot::PlotLine("##Open", xs, ys, 2); + spec.FillAlpha = 0.0f; + ImPlot::PlotLine("##Open", xs, ys, 2, spec); ImGui::PopID(); ys[0]--; ys[1]--; } @@ -951,7 +982,7 @@ void Demo_MarkersAndText() { ImPlot::PlotText("Open Markers", 7.5f, 6.0f); ImPlot::PushStyleColor(ImPlotCol_InlayText, ImVec4(1,0,1,1)); - ImPlot::PlotText("Vertical Text", 5.0f, 6.0f, ImVec2(0,0), ImPlotTextFlags_Vertical); + ImPlot::PlotText("Vertical Text", 5.0f, 6.0f, ImVec2(0,0), {ImProp_Flags, ImPlotTextFlags_Vertical}); ImPlot::PopStyleColor(); ImPlot::EndPlot(); @@ -976,8 +1007,10 @@ void Demo_NaNValues() { ImGui::CheckboxFlags("Skip NaN", (unsigned int*)&flags, ImPlotLineFlags_SkipNaN); if (ImPlot::BeginPlot("##NaNValues")) { - ImPlot::SetNextMarkerStyle(ImPlotMarker_Square); - ImPlot::PlotLine("line", data1, data2, 5, flags); + ImPlot::PlotLine("line", data1, data2, 5, { + ImProp_Flags, flags, + ImProp_Marker, ImPlotMarker_Square + }); ImPlot::PlotBars("bars", data1, 5); ImPlot::EndPlot(); } @@ -1059,7 +1092,7 @@ void Demo_TimeScale() { end = end < 0 ? 0 : end > HugeTimeData::Size - 1 ? HugeTimeData::Size - 1 : end; int size = (end - start)/downsample; // plot it - ImPlot::PlotLine("Time Series", &data->Ts[start], &data->Ys[start], size, 0, 0, sizeof(double)*downsample); + ImPlot::PlotLine("Time Series", &data->Ts[start], &data->Ys[start], size, {ImProp_Stride, sizeof(double)*downsample}); } // plot time now double t_now = (double)time(nullptr); @@ -1284,12 +1317,13 @@ void Demo_SubplotsSizing() { if (ImPlot::BeginPlot("",ImVec2(),ImPlotFlags_NoLegend)) { ImPlot::SetupAxes(nullptr,nullptr,ImPlotAxisFlags_NoDecorations,ImPlotAxisFlags_NoDecorations); float fi = 0.01f * (i+1); + ImVec4 col = GetColormapColor(0); if (rows*cols > 1) { - ImPlot::SetNextLineStyle(SampleColormap((float)i/(float)(rows*cols-1),ImPlotColormap_Jet)); + col = SampleColormap((float)i/(float)(rows*cols-1),ImPlotColormap_Jet); } char label[16]; snprintf(label, sizeof(label), "data%d", id++); - ImPlot::PlotLineG(label,SinewaveGetter,&fi,1000); + ImPlot::PlotLineG(label,SinewaveGetter,&fi,1000, {ImProp_LineColor, col}); ImPlot::EndPlot(); } } @@ -1443,12 +1477,22 @@ void Demo_DragPoints() { B[i] = ImPlotPoint(w1*P[0].x + w2*P[1].x + w3*P[2].x + w4*P[3].x, w1*P[0].y + w2*P[1].y + w3*P[2].y + w4*P[3].y); } - ImPlot::SetNextLineStyle(ImVec4(1,0.5f,1,1),hovered[1]||held[1] ? 2.0f : 1.0f); - ImPlot::PlotLine("##h1",&P[0].x, &P[0].y, 2, 0, 0, sizeof(ImPlotPoint)); - ImPlot::SetNextLineStyle(ImVec4(0,0.5f,1,1), hovered[2]||held[2] ? 2.0f : 1.0f); - ImPlot::PlotLine("##h2",&P[2].x, &P[2].y, 2, 0, 0, sizeof(ImPlotPoint)); - ImPlot::SetNextLineStyle(ImVec4(0,0.9f,0,1), hovered[0]||held[0]||hovered[3]||held[3] ? 3.0f : 2.0f); - ImPlot::PlotLine("##bez",&B[0].x, &B[0].y, 100, 0, 0, sizeof(ImPlotPoint)); + ImPlotSpec spec; + spec.Offset = 0; + spec.Stride = sizeof(ImPlotPoint); + + spec.LineColor = ImVec4(1,0.5f,1,1); + spec.LineWeight = hovered[1]||held[1] ? 2.0f : 1.0f; + ImPlot::PlotLine("##h1",&P[0].x, &P[0].y, 2, spec); + + spec.LineColor = ImVec4(0,0.5f,1,1); + spec.LineWeight = hovered[2]||held[2] ? 2.0f : 1.0f; + ImPlot::PlotLine("##h2",&P[2].x, &P[2].y, 2, spec); + + spec.LineColor = ImVec4(0,0.9f,0,1); + spec.LineWeight = hovered[0]||held[0]||hovered[3]||held[3] ? 3.0f : 2.0f; + ImPlot::PlotLine("##bez",&B[0].x, &B[0].y, 100, spec); + ImPlot::EndPlot(); } } @@ -1481,8 +1525,7 @@ void Demo_DragLines() { ys[i] = (y1+y2)/2+fabs(y2-y1)/2*sin(f*i/10); } ImPlot::DragLineY(120482,&f,ImVec4(1,0.5f,1,1),1,flags, &clicked, &hovered, &held); - ImPlot::SetNextLineStyle(IMPLOT_AUTO_COL, hovered||held ? 2.0f : 1.0f); - ImPlot::PlotLine("Interactive Data", xs, ys, 1000); + ImPlot::PlotLine("Interactive Data", xs, ys, 1000, {ImProp_LineWeight, hovered||held ? 2.0f : 1.0f}); ImPlot::EndPlot(); } } @@ -1592,14 +1635,19 @@ void Demo_Querying() { ImPlotPoint pt = ImPlot::GetPlotMousePos(); data.push_back(pt); } - ImPlot::PlotScatter("Points", &data[0].x, &data[0].y, data.size(), 0, 0, 2 * sizeof(double)); + ImPlotSpec spec; + spec.Offset = 0; + spec.Stride = 2 * sizeof(double); + ImPlotSpec cent_spec; + cent_spec.Marker = ImPlotMarker_Square; + cent_spec.Size = 6; + ImPlot::PlotScatter("Points", &data[0].x, &data[0].y, data.size(), spec); if (ImPlot::IsPlotSelected()) { select = ImPlot::GetPlotSelection(); int cnt; ImPlotPoint centroid = FindCentroid(data,select,cnt); if (cnt > 0) { - ImPlot::SetNextMarkerStyle(ImPlotMarker_Square,6); - ImPlot::PlotScatter("Centroid", ¢roid.x, ¢roid.y, 1); + ImPlot::PlotScatter("Centroid", ¢roid.x, ¢roid.y, 1, cent_spec); } if (ImGui::IsMouseClicked(ImPlot::GetInputMap().SelectCancel)) { CancelPlotSelection(); @@ -1610,8 +1658,7 @@ void Demo_Querying() { int cnt; ImPlotPoint centroid = FindCentroid(data,rects[i],cnt); if (cnt > 0) { - ImPlot::SetNextMarkerStyle(ImPlotMarker_Square,6); - ImPlot::PlotScatter("Centroid", ¢roid.x, ¢roid.y, 1); + ImPlot::PlotScatter("Centroid", ¢roid.x, ¢roid.y, 1, cent_spec); } ImPlot::DragRect(i,&rects[i].X.Min,&rects[i].Y.Min,&rects[i].X.Max,&rects[i].Y.Max,ImVec4(1,0,1,1)); } @@ -1750,8 +1797,11 @@ void Demo_DragAndDrop() { for (int k = 0; k < k_dnd; ++k) { if (dnd[k].Plt == 1 && dnd[k].Data.size() > 0) { ImPlot::SetAxis(dnd[k].Yax); - ImPlot::SetNextLineStyle(dnd[k].Color); - ImPlot::PlotLine(dnd[k].Label, &dnd[k].Data[0].x, &dnd[k].Data[0].y, dnd[k].Data.size(), 0, 0, 2 * sizeof(float)); + ImPlotSpec spec; + spec.Offset = 0; + spec.Stride = 2 * sizeof(float); + spec.LineColor = dnd[k].Color; + ImPlot::PlotLine(dnd[k].Label, &dnd[k].Data[0].x, &dnd[k].Data[0].y, dnd[k].Data.size(), spec); // allow legend item labels to be DND sources if (ImPlot::BeginDragDropSourceItem(dnd[k].Label)) { ImGui::SetDragDropPayload("MY_DND", &k, sizeof(int)); @@ -1795,8 +1845,11 @@ void Demo_DragAndDrop() { ImPlot::PopStyleColor(2); if (dndx != nullptr && dndy != nullptr) { ImVec4 mixed((dndx->Color.x + dndy->Color.x)/2,(dndx->Color.y + dndy->Color.y)/2,(dndx->Color.z + dndy->Color.z)/2,(dndx->Color.w + dndy->Color.w)/2); - ImPlot::SetNextLineStyle(mixed); - ImPlot::PlotLine("##dndxy", &dndx->Data[0].y, &dndy->Data[0].y, dndx->Data.size(), 0, 0, 2 * sizeof(float)); + ImPlotSpec spec; + spec.Offset = 0; + spec.Stride = 2 * sizeof(float); + spec.LineColor = mixed; + ImPlot::PlotLine("##dndxy", &dndx->Data[0].y, &dndy->Data[0].y, dndx->Data.size(), spec); } // allow the x-axis to be a DND target if (ImPlot::BeginDragDropTargetAxis(ImAxis_X1)) { @@ -1885,6 +1938,52 @@ void Demo_Tables() { //----------------------------------------------------------------------------- +void Demo_ItemStylingAndSpec() { + static ImVec2 data1[20]; + for (int i = 0; i < 20; ++i) { + data1[i].x = i * 1/19.0f; + data1[i].y = data1[i].x * data1[i].x; + } + static ImVec2 data2[20]; + for (int i = 0; i < 20; ++i) { + data2[i].x = i * 1/19.0f; + data2[i].y = data2[i].x * data2[i].x * data2[i].x; + } + if (ImPlot::BeginPlot("##SpecStyling")) { + ImPlot::SetupAxes("x","y"); + + // Two options for using ImPlotSpec: + + // 1. By declaring and defining a struct instance: + ImPlotSpec spec; + spec.LineColor = ImVec4(1,1,0,1); + spec.LineWeight = 1.0f; + spec.FillColor = ImVec4(1,0.5f,0,1); + spec.FillAlpha = 0.5f; + spec.Marker = ImPlotMarker_Square; + spec.Size = 6; + spec.Stride = sizeof(ImVec2); + spec.Flags = ImPlotItemFlags_NoLegend | ImPlotLineFlags_Shaded; + ImPlot::PlotLine("Line 1", &data1[0].x, &data1[0].y, 20, spec); + + // 2. Inline using ImProp,value pairs (order does NOT matter): + ImPlot::PlotLine("Line 2", &data2[0].x, &data2[0].y, 20, { + ImProp_LineColor, ImVec4(0,1,1,1), + ImProp_LineWeight, 1.0f, + ImProp_FillColor, ImVec4(0,0,1,1), + ImProp_FillAlpha, 0.5f, + ImProp_Marker, ImPlotMarker_Diamond, + ImProp_Size, 6, + ImProp_Stride, sizeof(ImVec2), + ImProp_Flags, ImPlotItemFlags_NoLegend | ImPlotLineFlags_Shaded + }); + + ImPlot::EndPlot(); + } +} + +//----------------------------------------------------------------------------- + void Demo_OffsetAndStride() { static const int k_circles = 11; static const int k_points_per = 50; @@ -1910,7 +2009,7 @@ void Demo_OffsetAndStride() { char buff[32]; for (int c = 0; c < k_circles; ++c) { snprintf(buff, sizeof(buff), "Circle %d", c); - ImPlot::PlotLine(buff, &interleaved_data[c*2 + 0], &interleaved_data[c*2 + 1], k_points_per, 0, offset, 2*k_circles*sizeof(double)); + ImPlot::PlotLine(buff, &interleaved_data[c*2 + 0], &interleaved_data[c*2 + 1], k_points_per, {ImProp_Offset, offset, ImProp_Stride, 2 * k_circles*sizeof(double)}); } ImPlot::EndPlot(); ImPlot::PopColormap(); @@ -1933,7 +2032,7 @@ void Demo_CustomDataAndGetters() { if (ImPlot::BeginPlot("##Custom Data")) { // custom structs using stride example: - ImPlot::PlotLine("Vector2f", &vec2_data[0].x, &vec2_data[0].y, 2, 0, 0, sizeof(MyImPlot::Vector2f) /* or sizeof(float) * 2 */); + ImPlot::PlotLine("Vector2f", &vec2_data[0].x, &vec2_data[0].y, 2, {ImProp_Stride, sizeof(MyImPlot::Vector2f)}); // custom getter example 1: ImPlot::PlotLineG("Spiral", MyImPlot::Spiral, nullptr, 1000); @@ -1943,9 +2042,7 @@ void Demo_CustomDataAndGetters() { static MyImPlot::WaveData data2(0.001, 0.2, 4, 0.25); ImPlot::PlotLineG("Waves", MyImPlot::SineWave, &data1, 1000); ImPlot::PlotLineG("Waves", MyImPlot::SawWave, &data2, 1000); - ImPlot::PushStyleVar(ImPlotStyleVar_FillAlpha, 0.25f); - ImPlot::PlotShadedG("Waves", MyImPlot::SineWave, &data1, MyImPlot::SawWave, &data2, 1000); - ImPlot::PopStyleVar(); + ImPlot::PlotShadedG("Waves", MyImPlot::SineWave, &data1, MyImPlot::SawWave, &data2, 1000, {ImProp_FillAlpha, 0.25f}); // you can also pass C++ lambdas: // auto lamda = [](void* data, int idx) { ... return ImPlotPoint(x,y); }; @@ -2069,18 +2166,29 @@ void Demo_LegendPopups() { if (ImPlot::BeginPlot("Right Click the Legend")) { ImPlot::SetupAxesLimits(0,100,-1,1); // rendering logic - ImPlot::PushStyleVar(ImPlotStyleVar_FillAlpha, alpha); if (!line) { - ImPlot::SetNextFillStyle(color); - ImPlot::PlotBars("Right Click Me", vals, 101); + ImPlot::PlotBars("Right Click Me", vals, 101, 0.67, 0, { + ImProp_FillAlpha, alpha, + ImProp_FillColor, color + }); } else { - if (markers) ImPlot::SetNextMarkerStyle(ImPlotMarker_Square); - ImPlot::SetNextLineStyle(color, thickness); - ImPlot::PlotLine("Right Click Me", vals, 101); - if (shaded) ImPlot::PlotShaded("Right Click Me",vals,101); + ImPlot::PlotLine("Right Click Me", vals, 101, 1, 0, { + ImProp_LineColor, color, + ImProp_LineWeight, thickness + }); + if (markers) { + ImPlot::PlotScatter("Right Click Me", vals, 101, 1, 0, { + ImProp_Marker, ImPlotMarker_Square, + ImProp_LineColor, color + }); + } + if (shaded) { + ImPlot::PlotShaded("Right Click Me",vals,101, 0, 1, 0, { + ImProp_FillAlpha, alpha, + }); + } } - ImPlot::PopStyleVar(); // custom legend context menu if (ImPlot::BeginLegendPopup("Right Click Me")) { ImGui::SliderFloat("Frequency",&frequency,0,1,"%0.2f"); @@ -2266,6 +2374,7 @@ void ShowDemoWindow(bool* p_open) { ImGui::EndTabItem(); } if (ImGui::BeginTabItem("Tools")) { + DemoHeader("Item Styling and Spec", Demo_ItemStylingAndSpec); DemoHeader("Offset and Stride", Demo_OffsetAndStride); DemoHeader("Drag Points", Demo_DragPoints); DemoHeader("Drag Lines", Demo_DragLines); @@ -2331,9 +2440,13 @@ void Sparkline(const char* id, const float* values, int count, float min_v, floa if (ImPlot::BeginPlot(id,size,ImPlotFlags_CanvasOnly)) { ImPlot::SetupAxes(nullptr,nullptr,ImPlotAxisFlags_NoDecorations,ImPlotAxisFlags_NoDecorations); ImPlot::SetupAxesLimits(0, count - 1, min_v, max_v, ImGuiCond_Always); - ImPlot::SetNextLineStyle(col); - ImPlot::SetNextFillStyle(col, 0.25); - ImPlot::PlotLine(id, values, count, 1, 0, ImPlotLineFlags_Shaded, offset); + ImPlot::PlotLine(id, values, count, 1, 0, { + ImProp_LineColor, col, + ImProp_FillColor, col, + ImProp_FillAlpha, 0.25f, + ImProp_Offset, offset, + ImProp_Flags, ImPlotLineFlags_Shaded + }); ImPlot::EndPlot(); } ImPlot::PopStyleVar(); @@ -2344,11 +2457,6 @@ void StyleSeaborn() { ImPlotStyle& style = ImPlot::GetStyle(); ImVec4* colors = style.Colors; - colors[ImPlotCol_Line] = IMPLOT_AUTO_COL; - colors[ImPlotCol_Fill] = IMPLOT_AUTO_COL; - colors[ImPlotCol_MarkerOutline] = IMPLOT_AUTO_COL; - colors[ImPlotCol_MarkerFill] = IMPLOT_AUTO_COL; - colors[ImPlotCol_ErrorBar] = ImVec4(0.00f, 0.00f, 0.00f, 1.00f); colors[ImPlotCol_FrameBg] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f); colors[ImPlotCol_PlotBg] = ImVec4(0.92f, 0.92f, 0.95f, 1.00f); colors[ImPlotCol_PlotBorder] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); @@ -2359,20 +2467,13 @@ void StyleSeaborn() { colors[ImPlotCol_InlayText] = ImVec4(0.00f, 0.00f, 0.00f, 1.00f); colors[ImPlotCol_AxisText] = ImVec4(0.00f, 0.00f, 0.00f, 1.00f); colors[ImPlotCol_AxisGrid] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f); - colors[ImPlotCol_AxisBgHovered] = ImVec4(0.92f, 0.92f, 0.95f, 1.00f); - colors[ImPlotCol_AxisBgActive] = ImVec4(0.92f, 0.92f, 0.95f, 0.75f); + colors[ImPlotCol_AxisBgHovered] = ImVec4(0.92f, 0.92f, 0.95f, 1.00f); + colors[ImPlotCol_AxisBgActive] = ImVec4(0.92f, 0.92f, 0.95f, 0.75f); colors[ImPlotCol_Selection] = ImVec4(1.00f, 0.65f, 0.00f, 1.00f); colors[ImPlotCol_Crosshairs] = ImVec4(0.23f, 0.10f, 0.64f, 0.50f); - style.LineWeight = 1.5; - style.Marker = ImPlotMarker_None; - style.MarkerSize = 4; - style.MarkerWeight = 1; - style.FillAlpha = 1.0f; - style.ErrorBarSize = 5; - style.ErrorBarWeight = 1.5f; - style.DigitalBitHeight = 8; - style.DigitalBitGap = 4; + style.MousePosPadding = ImVec2(5,5); + style.PlotMinSize = ImVec2(300,225); style.PlotBorderSize = 0; style.MinorAlpha = 1.0f; style.MajorTickLen = ImVec2(0,0); @@ -2384,15 +2485,15 @@ void StyleSeaborn() { style.PlotPadding = ImVec2(12,12); style.LabelPadding = ImVec2(5,5); style.LegendPadding = ImVec2(5,5); - style.MousePosPadding = ImVec2(5,5); - style.PlotMinSize = ImVec2(300,225); + style.DigitalPadding = 20; + style.DigitalSpacing = 4; } -} // namespaece MyImPlot +} // namespace MyImPlot // WARNING: // -// You can use "implot_internal.h" to build custom plotting fuctions or extend ImPlot. +// You can use "implot_internal.h" to build custom plotting functions or extend ImPlot. // However, note that forward compatibility of this file is not guaranteed and the // internal API is subject to change. At some point we hope to bring more of this // into the public API and expose the necessary building blocks to fully support diff --git a/implot_internal.h b/implot_internal.h index 8c1650ef..cefc8849 100644 --- a/implot_internal.h +++ b/implot_internal.h @@ -51,22 +51,25 @@ // Constants can be changed unless stated otherwise. We may move some of these // to ImPlotStyleVar_ over time. -// Mimimum allowable timestamp value 01/01/1970 @ 12:00am (UTC) (DO NOT DECREASE THIS) -#define IMPLOT_MIN_TIME 0 +// Minimum allowable timestamp value 01/01/1970 @ 12:00am (UTC) (DO NOT DECREASE THIS) +constexpr double IMPLOT_MIN_TIME = 0; // Maximum allowable timestamp value 01/01/3000 @ 12:00am (UTC) (DO NOT INCREASE THIS) -#define IMPLOT_MAX_TIME 32503680000 +constexpr double IMPLOT_MAX_TIME = 32503680000; + // Default label format for axis labels -#define IMPLOT_LABEL_FORMAT "%g" +constexpr const char* IMPLOT_LABEL_FORMAT = "%g"; // Max character size for tick labels -#define IMPLOT_LABEL_MAX_SIZE 32 +constexpr int IMPLOT_LABEL_MAX_SIZE = 32; + +// Number of X axes +constexpr int IMPLOT_NUM_X_AXES = ImAxis_Y1; +// Number of Y axes +constexpr int IMPLOT_NUM_Y_AXES = ImAxis_COUNT - IMPLOT_NUM_X_AXES; //----------------------------------------------------------------------------- // [SECTION] Macros //----------------------------------------------------------------------------- -#define IMPLOT_NUM_X_AXES ImAxis_Y1 -#define IMPLOT_NUM_Y_AXES (ImAxis_COUNT - IMPLOT_NUM_X_AXES) - // Split ImU32 color into RGB components [0 255] #define IM_COL32_SPLIT_RGB(col,r,g,b) \ ImU32 r = ((col >> IM_COL32_R_SHIFT) & 0xFF); \ @@ -133,16 +136,23 @@ static inline double ImConstrainLog(double val) { return val <= 0 ? 0.001f : val static inline double ImConstrainTime(double val) { return val < IMPLOT_MIN_TIME ? IMPLOT_MIN_TIME : (val > IMPLOT_MAX_TIME ? IMPLOT_MAX_TIME : val); } // True if two numbers are approximately equal using units in the last place. static inline bool ImAlmostEqual(double v1, double v2, int ulp = 2) { return ImAbs(v1-v2) < DBL_EPSILON * ImAbs(v1+v2) * ulp || ImAbs(v1-v2) < DBL_MIN; } + +// Template machinery to enable indexing C arrays, STL containers, and ImPlot Indexers/Getters. +template struct value_type { using type = typename TContainer::value_type; }; +template struct value_type { using type = T; }; +template struct value_type { using type = T; }; +template using value_type_t = typename value_type::type; + // Finds min value in an unsorted array -template -static inline T ImMinArray(const T* values, int count) { T m = values[0]; for (int i = 1; i < count; ++i) { if (values[i] < m) { m = values[i]; } } return m; } +template +static inline value_type_t ImMinArray(const TContainer& values, int count) { value_type_t m = values[0]; for (int i = 1; i < count; ++i) { if (values[i] < m) { m = values[i]; } } return m; } // Finds the max value in an unsorted array -template -static inline T ImMaxArray(const T* values, int count) { T m = values[0]; for (int i = 1; i < count; ++i) { if (values[i] > m) { m = values[i]; } } return m; } +template +static inline value_type_t ImMaxArray(const value_type_t& values, int count) { value_type_t m = values[0]; for (int i = 1; i < count; ++i) { if (values[i] > m) { m = values[i]; } } return m; } // Finds the min and max value in an unsorted array -template -static inline void ImMinMaxArray(const T* values, int count, T* min_out, T* max_out) { - T Min = values[0]; T Max = values[0]; +template +static inline void ImMinMaxArray(const TContainer& values, int count, value_type_t* min_out, value_type_t* max_out) { + value_type_t Min = values[0]; value_type_t Max = values[0]; for (int i = 1; i < count; ++i) { if (values[i] < Min) { Min = values[i]; } if (values[i] > Max) { Max = values[i]; } @@ -150,16 +160,16 @@ static inline void ImMinMaxArray(const T* values, int count, T* min_out, T* max_ *min_out = Min; *max_out = Max; } // Finds the sim of an array -template -static inline T ImSum(const T* values, int count) { - T sum = 0; +template +static inline value_type_t ImSum(const TContainer& values, int count) { + value_type_t sum = 0; for (int i = 0; i < count; ++i) sum += values[i]; return sum; } // Finds the mean of an array -template -static inline double ImMean(const T* values, int count) { +template +static inline double ImMean(const TContainer& values, int count) { double den = 1.0 / count; double mu = 0; for (int i = 0; i < count; ++i) @@ -167,8 +177,8 @@ static inline double ImMean(const T* values, int count) { return mu; } // Finds the sample standard deviation of an array -template -static inline double ImStdDev(const T* values, int count) { +template +static inline double ImStdDev(const TContainer& values, int count) { double den = 1.0 / (count - 1.0); double mu = ImMean(values, count); double x = 0; @@ -176,6 +186,7 @@ static inline double ImStdDev(const T* values, int count) { x += ((double)values[i] - mu) * ((double)values[i] - mu) * den; return sqrt(x); } + // Mix color a and b by factor s in [0 256] static inline ImU32 ImMixU32(ImU32 a, ImU32 b, ImU32 s) { #ifdef IMPLOT_MIX64 @@ -226,9 +237,10 @@ static inline bool ImOverlaps(T min_a, T max_a, T min_b, T max_b) { // [SECTION] ImPlot Enums //----------------------------------------------------------------------------- -typedef int ImPlotTimeUnit; // -> enum ImPlotTimeUnit_ -typedef int ImPlotDateFmt; // -> enum ImPlotDateFmt_ -typedef int ImPlotTimeFmt; // -> enum ImPlotTimeFmt_ +typedef int ImPlotTimeUnit; // -> enum ImPlotTimeUnit_ +typedef int ImPlotDateFmt; // -> enum ImPlotDateFmt_ +typedef int ImPlotTimeFmt; // -> enum ImPlotTimeFmt_ +typedef int ImPlotMarkerInternal; // -> enum ImPlotMarkerInternal_ enum ImPlotTimeUnit_ { ImPlotTimeUnit_Us, // microsecond @@ -264,6 +276,10 @@ enum ImPlotTimeFmt_ { // default [ 24 Hour Clock ] ImPlotTimeFmt_Hr // 7pm [ 19:00 ] }; +enum ImPlotMarkerInternal_ { + ImPlotMarker_Invalid = -3 +}; + //----------------------------------------------------------------------------- // [SECTION] Callbacks //----------------------------------------------------------------------------- @@ -731,7 +747,7 @@ struct ImPlotAxis PickerTimeMin = ImPlotTime::FromDouble(Range.Min); UpdateTransformCache(); return true; - }; + } inline bool SetMax(double _max, bool force=false) { if (!force && IsLockedMax()) @@ -750,7 +766,7 @@ struct ImPlotAxis PickerTimeMax = ImPlotTime::FromDouble(Range.Max); UpdateTransformCache(); return true; - }; + } inline void SetRange(double v1, double v2) { Range.Min = ImMin(v1,v2); @@ -941,6 +957,7 @@ struct ImPlotItem { ImGuiID ID; ImU32 Color; + ImPlotMarker Marker; ImRect LegendHoverRect; int NameOffset; bool Show; @@ -950,6 +967,7 @@ struct ImPlotItem ImPlotItem() { ID = 0; Color = IM_COL32_WHITE; + Marker = ImPlotMarker_None; NameOffset = -1; Show = true; SeenThisFrame = false; @@ -993,8 +1011,9 @@ struct ImPlotItemGroup ImPlotLegend Legend; ImPool ItemPool; int ColormapIdx; + ImPlotMarker MarkerIdx; - ImPlotItemGroup() { ID = 0; ColormapIdx = 0; } + ImPlotItemGroup() { ID = 0; ColormapIdx = 0; MarkerIdx = 0; } int GetItemCount() const { return ItemPool.GetBufSize(); } ImGuiID GetItemID(const char* label_id) { return ImGui::GetID(label_id); /* GetIDWithSeed */ } @@ -1173,30 +1192,18 @@ struct ImPlotNextPlotData // Temporary data storage for upcoming item struct ImPlotNextItemData { - ImVec4 Colors[5]; // ImPlotCol_Line, ImPlotCol_Fill, ImPlotCol_MarkerOutline, ImPlotCol_MarkerFill, ImPlotCol_ErrorBar - float LineWeight; - ImPlotMarker Marker; - float MarkerSize; - float MarkerWeight; - float FillAlpha; - float ErrorBarSize; - float ErrorBarWeight; - float DigitalBitHeight; - float DigitalBitGap; + ImPlotSpec Spec; bool RenderLine; bool RenderFill; - bool RenderMarkerLine; - bool RenderMarkerFill; + bool RenderMarkers; bool HasHidden; bool Hidden; ImPlotCond HiddenCond; ImPlotNextItemData() { Reset(); } void Reset() { - for (int i = 0; i < 5; ++i) - Colors[i] = IMPLOT_AUTO_COL; - LineWeight = MarkerSize = MarkerWeight = FillAlpha = ErrorBarSize = ErrorBarWeight = DigitalBitHeight = DigitalBitGap = IMPLOT_AUTO; - Marker = IMPLOT_AUTO; - HasHidden = Hidden = false; + Spec = ImPlotSpec(); + HasHidden = Hidden = false; + HiddenCond = ImPlotCond_None; } }; @@ -1309,14 +1316,14 @@ IMPLOT_API void ShowSubplotsContextMenu(ImPlotSubplot& subplot); //----------------------------------------------------------------------------- // Begins a new item. Returns false if the item should not be plotted. Pushes PlotClipRect. -IMPLOT_API bool BeginItem(const char* label_id, ImPlotItemFlags flags=0, ImPlotCol recolor_from=IMPLOT_AUTO); +IMPLOT_API bool BeginItem(const char* label_id, const ImPlotSpec& spec = ImPlotSpec(), const ImVec4& item_col = IMPLOT_AUTO_COL, ImPlotMarker item_mkr = ImPlotMarker_Invalid); // Same as above but with fitting functionality. template -bool BeginItemEx(const char* label_id, const _Fitter& fitter, ImPlotItemFlags flags=0, ImPlotCol recolor_from=IMPLOT_AUTO) { - if (BeginItem(label_id, flags, recolor_from)) { +bool BeginItemEx(const char* label_id, const _Fitter& fitter, const ImPlotSpec& spec, const ImVec4& item_col = IMPLOT_AUTO_COL, ImPlotMarker item_mkr = ImPlotMarker_Invalid) { + if (BeginItem(label_id, spec, item_col, item_mkr)) { ImPlotPlot& plot = *GetCurrentPlot(); - if (plot.FitThisFrame && !ImHasFlag(flags, ImPlotItemFlags_NoFit)) + if (plot.FitThisFrame && !ImHasFlag(spec.Flags, ImPlotItemFlags_NoFit)) fitter.Fit(plot.Axes[plot.CurrentX], plot.Axes[plot.CurrentY]); return true; } @@ -1517,8 +1524,8 @@ void FillRange(ImVector& buffer, int n, T vmin, T vmax) { } // Calculate histogram bin counts and widths -template -static inline void CalculateBins(const T* values, int count, ImPlotBin meth, const ImPlotRange& range, int& bins_out, double& width_out) { +template +static inline void CalculateBins(const TContainer& values, int count, ImPlotBin meth, const ImPlotRange& range, int& bins_out, double& width_out) { switch (meth) { case ImPlotBin_Sqrt: bins_out = (int)ceil(sqrt(count)); @@ -1547,7 +1554,7 @@ static inline bool IsLeapYear(int year) { } // Returns the number of days in a month, accounting for Feb. leap years. #month is zero indexed. static inline int GetDaysInMonth(int year, int month) { - static const int days[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; + constexpr int days[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; return days[month] + (int)(month == 1 && IsLeapYear(year)); } diff --git a/implot_items.cpp b/implot_items.cpp index 91c71d82..749a46ae 100644 --- a/implot_items.cpp +++ b/implot_items.cpp @@ -115,7 +115,12 @@ template struct MaxIdx { static const unsigned int Value; }; template <> const unsigned int MaxIdx::Value = 65535; template <> const unsigned int MaxIdx::Value = 4294967295; - + +template +int Stride(const ImPlotSpec& spec) { + return spec.Stride == IMPLOT_AUTO ? sizeof(T) : spec.Stride; +} + IMPLOT_INLINE void GetLineRenderProps(const ImDrawList& draw_list, float& half_weight, ImVec2& tex_uv0, ImVec2& tex_uv1) { const bool aa = ImHasFlag(draw_list.Flags, ImDrawListFlags_AntiAliasedLines) && ImHasFlag(draw_list.Flags, ImDrawListFlags_AntiAliasedLinesUseTex); @@ -319,34 +324,6 @@ ImPlotItem* GetCurrentItem() { return gp.CurrentItem; } -void SetNextLineStyle(const ImVec4& col, float weight) { - ImPlotContext& gp = *GImPlot; - gp.NextItemData.Colors[ImPlotCol_Line] = col; - gp.NextItemData.LineWeight = weight; -} - -void SetNextFillStyle(const ImVec4& col, float alpha) { - ImPlotContext& gp = *GImPlot; - gp.NextItemData.Colors[ImPlotCol_Fill] = col; - gp.NextItemData.FillAlpha = alpha; -} - -void SetNextMarkerStyle(ImPlotMarker marker, float size, const ImVec4& fill, float weight, const ImVec4& outline) { - ImPlotContext& gp = *GImPlot; - gp.NextItemData.Marker = marker; - gp.NextItemData.Colors[ImPlotCol_MarkerFill] = fill; - gp.NextItemData.MarkerSize = size; - gp.NextItemData.Colors[ImPlotCol_MarkerOutline] = outline; - gp.NextItemData.MarkerWeight = weight; -} - -void SetNextErrorBarStyle(const ImVec4& col, float size, float weight) { - ImPlotContext& gp = *GImPlot; - gp.NextItemData.Colors[ImPlotCol_ErrorBar] = col; - gp.NextItemData.ErrorBarSize = size; - gp.NextItemData.ErrorBarWeight = weight; -} - ImVec4 GetLastItemColor() { ImPlotContext& gp = *GImPlot; if (gp.PreviousItem) @@ -388,36 +365,41 @@ void BustColorCache(const char* plot_title_id) { // [SECTION] BeginItem / EndItem //----------------------------------------------------------------------------- -static const float ITEM_HIGHLIGHT_LINE_SCALE = 2.0f; -static const float ITEM_HIGHLIGHT_MARK_SCALE = 1.25f; +constexpr float ITEM_HIGHLIGHT_LINE_SCALE = 2.0f; +constexpr float ITEM_HIGHLIGHT_MARK_SCALE = 1.25f; // Begins a new item. Returns false if the item should not be plotted. -bool BeginItem(const char* label_id, ImPlotItemFlags flags, ImPlotCol recolor_from) { +bool BeginItem(const char* label_id, const ImPlotSpec& spec, const ImVec4& item_col, ImPlotMarker item_mkr) { ImPlotContext& gp = *GImPlot; IM_ASSERT_USER_ERROR(gp.CurrentPlot != nullptr, "PlotX() needs to be called between BeginPlot() and EndPlot()!"); SetupLock(); bool just_created; - ImPlotItem* item = RegisterOrGetItem(label_id, flags, &just_created); + ImPlotItem* item = RegisterOrGetItem(label_id, spec.Flags, &just_created); // set current item gp.CurrentItem = item; ImPlotNextItemData& s = gp.NextItemData; // set/override item color - if (recolor_from != -1) { - if (!IsColorAuto(s.Colors[recolor_from])) - item->Color = ImGui::ColorConvertFloat4ToU32(s.Colors[recolor_from]); - else if (!IsColorAuto(gp.Style.Colors[recolor_from])) - item->Color = ImGui::ColorConvertFloat4ToU32(gp.Style.Colors[recolor_from]); - else if (just_created) - item->Color = NextColormapColorU32(); - } - else if (just_created) { + if (!IsColorAuto(item_col)) + item->Color = ImGui::ColorConvertFloat4ToU32(item_col); + else if (just_created) item->Color = NextColormapColorU32(); - } - // hide/show item if (gp.NextItemData.HasHidden) { if (just_created || gp.NextItemData.HiddenCond == ImGuiCond_Always) item->Show = !gp.NextItemData.Hidden; } + // set/override item marker + if (item_mkr != ImPlotMarker_Invalid) { + if (item_mkr != ImPlotMarker_Auto) { + item->Marker = item_mkr; + } + else if (just_created && item_mkr == ImPlotMarker_Auto) { + item->Marker = NextMarker(); + } + else if (item_mkr == ImPlotMarker_Auto && item->Marker == ImPlotMarker_None) { + item->Marker = NextMarker(); + } + } + // return false if not shown if (!item->Show) { // reset next item data gp.NextItemData.Reset(); @@ -427,32 +409,18 @@ bool BeginItem(const char* label_id, ImPlotItemFlags flags, ImPlotCol recolor_fr } else { ImVec4 item_color = ImGui::ColorConvertU32ToFloat4(item->Color); - // stage next item colors - s.Colors[ImPlotCol_Line] = IsColorAuto(s.Colors[ImPlotCol_Line]) ? ( IsColorAuto(ImPlotCol_Line) ? item_color : gp.Style.Colors[ImPlotCol_Line] ) : s.Colors[ImPlotCol_Line]; - s.Colors[ImPlotCol_Fill] = IsColorAuto(s.Colors[ImPlotCol_Fill]) ? ( IsColorAuto(ImPlotCol_Fill) ? item_color : gp.Style.Colors[ImPlotCol_Fill] ) : s.Colors[ImPlotCol_Fill]; - s.Colors[ImPlotCol_MarkerOutline] = IsColorAuto(s.Colors[ImPlotCol_MarkerOutline]) ? ( IsColorAuto(ImPlotCol_MarkerOutline) ? s.Colors[ImPlotCol_Line] : gp.Style.Colors[ImPlotCol_MarkerOutline] ) : s.Colors[ImPlotCol_MarkerOutline]; - s.Colors[ImPlotCol_MarkerFill] = IsColorAuto(s.Colors[ImPlotCol_MarkerFill]) ? ( IsColorAuto(ImPlotCol_MarkerFill) ? s.Colors[ImPlotCol_Line] : gp.Style.Colors[ImPlotCol_MarkerFill] ) : s.Colors[ImPlotCol_MarkerFill]; - s.Colors[ImPlotCol_ErrorBar] = IsColorAuto(s.Colors[ImPlotCol_ErrorBar]) ? ( GetStyleColorVec4(ImPlotCol_ErrorBar) ) : s.Colors[ImPlotCol_ErrorBar]; - // stage next item style vars - s.LineWeight = s.LineWeight < 0 ? gp.Style.LineWeight : s.LineWeight; - s.Marker = s.Marker < 0 ? gp.Style.Marker : s.Marker; - s.MarkerSize = s.MarkerSize < 0 ? gp.Style.MarkerSize : s.MarkerSize; - s.MarkerWeight = s.MarkerWeight < 0 ? gp.Style.MarkerWeight : s.MarkerWeight; - s.FillAlpha = s.FillAlpha < 0 ? gp.Style.FillAlpha : s.FillAlpha; - s.ErrorBarSize = s.ErrorBarSize < 0 ? gp.Style.ErrorBarSize : s.ErrorBarSize; - s.ErrorBarWeight = s.ErrorBarWeight < 0 ? gp.Style.ErrorBarWeight : s.ErrorBarWeight; - s.DigitalBitHeight = s.DigitalBitHeight < 0 ? gp.Style.DigitalBitHeight : s.DigitalBitHeight; - s.DigitalBitGap = s.DigitalBitGap < 0 ? gp.Style.DigitalBitGap : s.DigitalBitGap; - // apply alpha modifier(s) - s.Colors[ImPlotCol_Fill].w *= s.FillAlpha; - s.Colors[ImPlotCol_MarkerFill].w *= s.FillAlpha; // TODO: this should be separate, if it at all + // stage next item spec + s.Spec = spec; + s.Spec.LineColor = IsColorAuto(s.Spec.LineColor) ? item_color : s.Spec.LineColor; + s.Spec.FillColor = IsColorAuto(s.Spec.FillColor) ? s.Spec.LineColor : s.Spec.FillColor; + s.Spec.FillColor.w *= s.Spec.FillAlpha; + s.Spec.Marker = item->Marker; // apply highlight mods if (item->LegendHovered) { if (!ImHasFlag(gp.CurrentItems->Legend.Flags, ImPlotLegendFlags_NoHighlightItem)) { - s.LineWeight *= ITEM_HIGHLIGHT_LINE_SCALE; - s.MarkerSize *= ITEM_HIGHLIGHT_MARK_SCALE; - s.MarkerWeight *= ITEM_HIGHLIGHT_LINE_SCALE; - // TODO: how to highlight fills? + s.Spec.LineWeight *= ITEM_HIGHLIGHT_LINE_SCALE; + s.Spec.Size *= ITEM_HIGHLIGHT_MARK_SCALE; + // TODO: how to highlight fills? } if (!ImHasFlag(gp.CurrentItems->Legend.Flags, ImPlotLegendFlags_NoHighlightAxis)) { if (gp.CurrentPlot->EnabledAxesX() > 1) @@ -462,10 +430,9 @@ bool BeginItem(const char* label_id, ImPlotItemFlags flags, ImPlotCol recolor_fr } } // set render flags - s.RenderLine = s.Colors[ImPlotCol_Line].w > 0 && s.LineWeight > 0; - s.RenderFill = s.Colors[ImPlotCol_Fill].w > 0; - s.RenderMarkerFill = s.Colors[ImPlotCol_MarkerFill].w > 0; - s.RenderMarkerLine = s.Colors[ImPlotCol_MarkerOutline].w > 0 && s.MarkerWeight > 0; + s.RenderLine = s.Spec.LineColor.w > 0 && s.Spec.LineWeight > 0; + s.RenderFill = s.Spec.FillColor.w > 0; + s.RenderMarkers = s.Spec.Marker >= 0 && (s.RenderFill || s.RenderLine); // push rendering clip rect PushPlotClipRect(); return true; @@ -508,13 +475,14 @@ struct IndexerIdx { Offset(count ? ImPosMod(offset, count) : 0), Stride(stride) { } - template IMPLOT_INLINE double operator()(I idx) const { + template IMPLOT_INLINE double operator[](I idx) const { return (double)IndexData(Data, idx, Count, Offset, Stride); } const T* Data; int Count; int Offset; int Stride; + typedef double value_type; }; template @@ -526,29 +494,32 @@ struct IndexerAdd { Scale2(scale2), Count(ImMin(Indexer1.Count, Indexer2.Count)) { } - template IMPLOT_INLINE double operator()(I idx) const { - return Scale1 * Indexer1(idx) + Scale2 * Indexer2(idx); + template IMPLOT_INLINE double operator[](I idx) const { + return Scale1 * Indexer1[idx] + Scale2 * Indexer2[idx]; } const _Indexer1& Indexer1; const _Indexer2& Indexer2; double Scale1; double Scale2; int Count; + typedef double value_type; }; struct IndexerLin { IndexerLin(double m, double b) : M(m), B(b) { } - template IMPLOT_INLINE double operator()(I idx) const { + template IMPLOT_INLINE double operator[](I idx) const { return M * idx + B; } const double M; const double B; + typedef double value_type; }; struct IndexerConst { IndexerConst(double ref) : Ref(ref) { } - template IMPLOT_INLINE double operator()(I) const { return Ref; } + template IMPLOT_INLINE double operator[](I) const { return Ref; } const double Ref; + typedef double value_type; }; //----------------------------------------------------------------------------- @@ -557,13 +528,14 @@ struct IndexerConst { template struct GetterXY { - GetterXY(_IndexerX x, _IndexerY y, int count) : IndxerX(x), IndxerY(y), Count(count) { } - template IMPLOT_INLINE ImPlotPoint operator()(I idx) const { - return ImPlotPoint(IndxerX(idx),IndxerY(idx)); + GetterXY(_IndexerX x, _IndexerY y, int count) : IndexerX(x), IndexerY(y), Count(count) { } + template IMPLOT_INLINE ImPlotPoint operator[](I idx) const { + return ImPlotPoint(IndexerX[idx],IndexerY[idx]); } - const _IndexerX IndxerX; - const _IndexerY IndxerY; + const _IndexerX IndexerX; + const _IndexerY IndexerY; const int Count; + typedef ImPlotPoint value_type; }; /// Interprets a user's function pointer as ImPlotPoints @@ -573,49 +545,53 @@ struct GetterFuncPtr { Data(data), Count(count) { } - template IMPLOT_INLINE ImPlotPoint operator()(I idx) const { + template IMPLOT_INLINE ImPlotPoint operator[](I idx) const { return Getter(idx, Data); } ImPlotGetter Getter; void* const Data; const int Count; + typedef ImPlotPoint value_type; }; template struct GetterOverrideX { GetterOverrideX(_Getter getter, double x) : Getter(getter), X(x), Count(getter.Count) { } - template IMPLOT_INLINE ImPlotPoint operator()(I idx) const { - ImPlotPoint p = Getter(idx); + template IMPLOT_INLINE ImPlotPoint operator[](I idx) const { + ImPlotPoint p = Getter[idx]; p.x = X; return p; } const _Getter Getter; const double X; const int Count; + typedef ImPlotPoint value_type; }; template struct GetterOverrideY { GetterOverrideY(_Getter getter, double y) : Getter(getter), Y(y), Count(getter.Count) { } - template IMPLOT_INLINE ImPlotPoint operator()(I idx) const { - ImPlotPoint p = Getter(idx); + template IMPLOT_INLINE ImPlotPoint operator[](I idx) const { + ImPlotPoint p = Getter[idx]; p.y = Y; return p; } const _Getter Getter; const double Y; const int Count; + typedef ImPlotPoint value_type; }; template struct GetterLoop { GetterLoop(_Getter getter) : Getter(getter), Count(getter.Count + 1) { } - template IMPLOT_INLINE ImPlotPoint operator()(I idx) const { + template IMPLOT_INLINE ImPlotPoint operator[](I idx) const { idx = idx % (Count - 1); - return Getter(idx); + return Getter[idx]; } const _Getter Getter; const int Count; + typedef ImPlotPoint value_type; }; template @@ -629,7 +605,7 @@ struct GetterError { Offset(count ? ImPosMod(offset, count) : 0), Stride(stride) { } - template IMPLOT_INLINE ImPlotPointError operator()(I idx) const { + template IMPLOT_INLINE ImPlotPointError operator[](I idx) const { return ImPlotPointError((double)IndexData(Xs, idx, Count, Offset, Stride), (double)IndexData(Ys, idx, Count, Offset, Stride), (double)IndexData(Neg, idx, Count, Offset, Stride), @@ -642,6 +618,7 @@ struct GetterError { const int Count; const int Offset; const int Stride; + typedef ImPlotPointError value_type; }; //----------------------------------------------------------------------------- @@ -653,7 +630,7 @@ struct Fitter1 { Fitter1(const _Getter1& getter) : Getter(getter) { } void Fit(ImPlotAxis& x_axis, ImPlotAxis& y_axis) const { for (int i = 0; i < Getter.Count; ++i) { - ImPlotPoint p = Getter(i); + ImPlotPoint p = Getter[i]; x_axis.ExtendFitWith(y_axis, p.x, p.y); y_axis.ExtendFitWith(x_axis, p.y, p.x); } @@ -666,7 +643,7 @@ struct FitterX { FitterX(const _Getter1& getter) : Getter(getter) { } void Fit(ImPlotAxis& x_axis, ImPlotAxis&) const { for (int i = 0; i < Getter.Count; ++i) { - ImPlotPoint p = Getter(i); + ImPlotPoint p = Getter[i]; x_axis.ExtendFit(p.x); } } @@ -678,7 +655,7 @@ struct FitterY { FitterY(const _Getter1& getter) : Getter(getter) { } void Fit(ImPlotAxis&, ImPlotAxis& y_axis) const { for (int i = 0; i < Getter.Count; ++i) { - ImPlotPoint p = Getter(i); + ImPlotPoint p = Getter[i]; y_axis.ExtendFit(p.y); } } @@ -690,12 +667,12 @@ struct Fitter2 { Fitter2(const _Getter1& getter1, const _Getter2& getter2) : Getter1(getter1), Getter2(getter2) { } void Fit(ImPlotAxis& x_axis, ImPlotAxis& y_axis) const { for (int i = 0; i < Getter1.Count; ++i) { - ImPlotPoint p = Getter1(i); + ImPlotPoint p = Getter1[i]; x_axis.ExtendFitWith(y_axis, p.x, p.y); y_axis.ExtendFitWith(x_axis, p.y, p.x); } for (int i = 0; i < Getter2.Count; ++i) { - ImPlotPoint p = Getter2(i); + ImPlotPoint p = Getter2[i]; x_axis.ExtendFitWith(y_axis, p.x, p.y); y_axis.ExtendFitWith(x_axis, p.y, p.x); } @@ -714,8 +691,8 @@ struct FitterBarV { void Fit(ImPlotAxis& x_axis, ImPlotAxis& y_axis) const { int count = ImMin(Getter1.Count, Getter2.Count); for (int i = 0; i < count; ++i) { - ImPlotPoint p1 = Getter1(i); p1.x -= HalfWidth; - ImPlotPoint p2 = Getter2(i); p2.x += HalfWidth; + ImPlotPoint p1 = Getter1[i]; p1.x -= HalfWidth; + ImPlotPoint p2 = Getter2[i]; p2.x += HalfWidth; x_axis.ExtendFitWith(y_axis, p1.x, p1.y); y_axis.ExtendFitWith(x_axis, p1.y, p1.x); x_axis.ExtendFitWith(y_axis, p2.x, p2.y); @@ -737,8 +714,8 @@ struct FitterBarH { void Fit(ImPlotAxis& x_axis, ImPlotAxis& y_axis) const { int count = ImMin(Getter1.Count, Getter2.Count); for (int i = 0; i < count; ++i) { - ImPlotPoint p1 = Getter1(i); p1.y -= HalfHeight; - ImPlotPoint p2 = Getter2(i); p2.y += HalfHeight; + ImPlotPoint p1 = Getter1[i]; p1.y -= HalfHeight; + ImPlotPoint p2 = Getter2[i]; p2.y += HalfHeight; x_axis.ExtendFitWith(y_axis, p1.x, p1.y); y_axis.ExtendFitWith(x_axis, p1.y, p1.x); x_axis.ExtendFitWith(y_axis, p2.x, p2.y); @@ -868,13 +845,13 @@ struct RendererLineStrip : RendererBase { Col(col), HalfWeight(ImMax(1.0f,weight)*0.5f) { - P1 = this->Transformer(Getter(0)); + P1 = this->Transformer(Getter[0]); } void Init(ImDrawList& draw_list) const { GetLineRenderProps(draw_list, HalfWeight, UV0, UV1); } IMPLOT_INLINE bool Render(ImDrawList& draw_list, const ImRect& cull_rect, int prim) const { - ImVec2 P2 = this->Transformer(Getter(prim + 1)); + ImVec2 P2 = this->Transformer(Getter[prim + 1]); if (!cull_rect.Overlaps(ImRect(ImMin(P1, P2), ImMax(P1, P2)))) { P1 = P2; return false; @@ -899,13 +876,13 @@ struct RendererLineStripSkip : RendererBase { Col(col), HalfWeight(ImMax(1.0f,weight)*0.5f) { - P1 = this->Transformer(Getter(0)); + P1 = this->Transformer(Getter[0]); } void Init(ImDrawList& draw_list) const { GetLineRenderProps(draw_list, HalfWeight, UV0, UV1); } IMPLOT_INLINE bool Render(ImDrawList& draw_list, const ImRect& cull_rect, int prim) const { - ImVec2 P2 = this->Transformer(Getter(prim + 1)); + ImVec2 P2 = this->Transformer(Getter[prim + 1]); if (!cull_rect.Overlaps(ImRect(ImMin(P1, P2), ImMax(P1, P2)))) { if (!ImNan(P2.x) && !ImNan(P2.y)) P1 = P2; @@ -936,8 +913,8 @@ struct RendererLineSegments1 : RendererBase { GetLineRenderProps(draw_list, HalfWeight, UV0, UV1); } IMPLOT_INLINE bool Render(ImDrawList& draw_list, const ImRect& cull_rect, int prim) const { - ImVec2 P1 = this->Transformer(Getter(prim*2+0)); - ImVec2 P2 = this->Transformer(Getter(prim*2+1)); + ImVec2 P1 = this->Transformer(Getter[prim*2+0]); + ImVec2 P2 = this->Transformer(Getter[prim*2+1]); if (!cull_rect.Overlaps(ImRect(ImMin(P1, P2), ImMax(P1, P2)))) return false; PrimLine(draw_list,P1,P2,HalfWeight,Col,UV0,UV1); @@ -963,8 +940,8 @@ struct RendererLineSegments2 : RendererBase { GetLineRenderProps(draw_list, HalfWeight, UV0, UV1); } IMPLOT_INLINE bool Render(ImDrawList& draw_list, const ImRect& cull_rect, int prim) const { - ImVec2 P1 = this->Transformer(Getter1(prim)); - ImVec2 P2 = this->Transformer(Getter2(prim)); + ImVec2 P1 = this->Transformer(Getter1[prim]); + ImVec2 P2 = this->Transformer(Getter2[prim]); if (!cull_rect.Overlaps(ImRect(ImMin(P1, P2), ImMax(P1, P2)))) return false; PrimLine(draw_list,P1,P2,HalfWeight,Col,UV0,UV1); @@ -991,8 +968,8 @@ struct RendererBarsFillV : RendererBase { UV = draw_list._Data->TexUvWhitePixel; } IMPLOT_INLINE bool Render(ImDrawList& draw_list, const ImRect& cull_rect, int prim) const { - ImPlotPoint p1 = Getter1(prim); - ImPlotPoint p2 = Getter2(prim); + ImPlotPoint p1 = Getter1[prim]; + ImPlotPoint p2 = Getter2[prim]; p1.x += HalfWidth; p2.x -= HalfWidth; ImVec2 P1 = this->Transformer(p1); @@ -1029,8 +1006,8 @@ struct RendererBarsFillH : RendererBase { UV = draw_list._Data->TexUvWhitePixel; } IMPLOT_INLINE bool Render(ImDrawList& draw_list, const ImRect& cull_rect, int prim) const { - ImPlotPoint p1 = Getter1(prim); - ImPlotPoint p2 = Getter2(prim); + ImPlotPoint p1 = Getter1[prim]; + ImPlotPoint p2 = Getter2[prim]; p1.y += HalfHeight; p2.y -= HalfHeight; ImVec2 P1 = this->Transformer(p1); @@ -1068,8 +1045,8 @@ struct RendererBarsLineV : RendererBase { UV = draw_list._Data->TexUvWhitePixel; } IMPLOT_INLINE bool Render(ImDrawList& draw_list, const ImRect& cull_rect, int prim) const { - ImPlotPoint p1 = Getter1(prim); - ImPlotPoint p2 = Getter2(prim); + ImPlotPoint p1 = Getter1[prim]; + ImPlotPoint p2 = Getter2[prim]; p1.x += HalfWidth; p2.x -= HalfWidth; ImVec2 P1 = this->Transformer(p1); @@ -1108,8 +1085,8 @@ struct RendererBarsLineH : RendererBase { UV = draw_list._Data->TexUvWhitePixel; } IMPLOT_INLINE bool Render(ImDrawList& draw_list, const ImRect& cull_rect, int prim) const { - ImPlotPoint p1 = Getter1(prim); - ImPlotPoint p2 = Getter2(prim); + ImPlotPoint p1 = Getter1[prim]; + ImPlotPoint p2 = Getter2[prim]; p1.y += HalfHeight; p2.y -= HalfHeight; ImVec2 P1 = this->Transformer(p1); @@ -1143,13 +1120,13 @@ struct RendererStairsPre : RendererBase { Col(col), HalfWeight(ImMax(1.0f,weight)*0.5f) { - P1 = this->Transformer(Getter(0)); + P1 = this->Transformer(Getter[0]); } void Init(ImDrawList& draw_list) const { UV = draw_list._Data->TexUvWhitePixel; } IMPLOT_INLINE bool Render(ImDrawList& draw_list, const ImRect& cull_rect, int prim) const { - ImVec2 P2 = this->Transformer(Getter(prim + 1)); + ImVec2 P2 = this->Transformer(Getter[prim + 1]); if (!cull_rect.Overlaps(ImRect(ImMin(P1, P2), ImMax(P1, P2)))) { P1 = P2; return false; @@ -1174,13 +1151,13 @@ struct RendererStairsPost : RendererBase { Col(col), HalfWeight(ImMax(1.0f,weight) * 0.5f) { - P1 = this->Transformer(Getter(0)); + P1 = this->Transformer(Getter[0]); } void Init(ImDrawList& draw_list) const { UV = draw_list._Data->TexUvWhitePixel; } IMPLOT_INLINE bool Render(ImDrawList& draw_list, const ImRect& cull_rect, int prim) const { - ImVec2 P2 = this->Transformer(Getter(prim + 1)); + ImVec2 P2 = this->Transformer(Getter[prim + 1]); if (!cull_rect.Overlaps(ImRect(ImMin(P1, P2), ImMax(P1, P2)))) { P1 = P2; return false; @@ -1204,14 +1181,14 @@ struct RendererStairsPreShaded : RendererBase { Getter(getter), Col(col) { - P1 = this->Transformer(Getter(0)); + P1 = this->Transformer(Getter[0]); Y0 = this->Transformer(ImPlotPoint(0,0)).y; } void Init(ImDrawList& draw_list) const { UV = draw_list._Data->TexUvWhitePixel; } IMPLOT_INLINE bool Render(ImDrawList& draw_list, const ImRect& cull_rect, int prim) const { - ImVec2 P2 = this->Transformer(Getter(prim + 1)); + ImVec2 P2 = this->Transformer(Getter[prim + 1]); ImVec2 PMin(ImMin(P1.x, P2.x), ImMin(Y0, P2.y)); ImVec2 PMax(ImMax(P1.x, P2.x), ImMax(Y0, P2.y)); if (!cull_rect.Overlaps(ImRect(PMin, PMax))) { @@ -1236,14 +1213,14 @@ struct RendererStairsPostShaded : RendererBase { Getter(getter), Col(col) { - P1 = this->Transformer(Getter(0)); + P1 = this->Transformer(Getter[0]); Y0 = this->Transformer(ImPlotPoint(0,0)).y; } void Init(ImDrawList& draw_list) const { UV = draw_list._Data->TexUvWhitePixel; } IMPLOT_INLINE bool Render(ImDrawList& draw_list, const ImRect& cull_rect, int prim) const { - ImVec2 P2 = this->Transformer(Getter(prim + 1)); + ImVec2 P2 = this->Transformer(Getter[prim + 1]); ImVec2 PMin(ImMin(P1.x, P2.x), ImMin(P1.y, Y0)); ImVec2 PMax(ImMax(P1.x, P2.x), ImMax(P1.y, Y0)); if (!cull_rect.Overlaps(ImRect(PMin, PMax))) { @@ -1271,15 +1248,15 @@ struct RendererShaded : RendererBase { Getter2(getter2), Col(col) { - P11 = this->Transformer(Getter1(0)); - P12 = this->Transformer(Getter2(0)); + P11 = this->Transformer(Getter1[0]); + P12 = this->Transformer(Getter2[0]); } void Init(ImDrawList& draw_list) const { UV = draw_list._Data->TexUvWhitePixel; } IMPLOT_INLINE bool Render(ImDrawList& draw_list, const ImRect& cull_rect, int prim) const { - ImVec2 P21 = this->Transformer(Getter1(prim+1)); - ImVec2 P22 = this->Transformer(Getter2(prim+1)); + ImVec2 P21 = this->Transformer(Getter1[prim+1]); + ImVec2 P22 = this->Transformer(Getter2[prim+1]); ImRect rect(ImMin(ImMin(ImMin(P11,P12),P21),P22), ImMax(ImMax(ImMax(P11,P12),P21),P22)); if (!cull_rect.Overlaps(rect)) { P11 = P21; @@ -1340,7 +1317,7 @@ struct RendererRectC : RendererBase { UV = draw_list._Data->TexUvWhitePixel; } IMPLOT_INLINE bool Render(ImDrawList& draw_list, const ImRect& cull_rect, int prim) const { - RectC rect = Getter(prim); + RectC rect = Getter[prim]; ImVec2 P1 = this->Transformer(rect.Pos.x - rect.HalfSize.x , rect.Pos.y - rect.HalfSize.y); ImVec2 P2 = this->Transformer(rect.Pos.x + rect.HalfSize.x , rect.Pos.y + rect.HalfSize.y); if ((rect.Color & IM_COL32_A_MASK) == 0 || !cull_rect.Overlaps(ImRect(ImMin(P1, P2), ImMax(P1, P2)))) @@ -1428,7 +1405,7 @@ struct RendererMarkersFill : RendererBase { UV = draw_list._Data->TexUvWhitePixel; } IMPLOT_INLINE bool Render(ImDrawList& draw_list, const ImRect& cull_rect, int prim) const { - ImVec2 p = this->Transformer(Getter(prim)); + ImVec2 p = this->Transformer(Getter[prim]); if (p.x >= cull_rect.Min.x && p.y >= cull_rect.Min.y && p.x <= cull_rect.Max.x && p.y <= cull_rect.Max.y) { for (int i = 0; i < Count; i++) { draw_list._VtxWritePtr[0].pos.x = p.x + Marker[i].x * Size; @@ -1472,7 +1449,7 @@ struct RendererMarkersLine : RendererBase { GetLineRenderProps(draw_list, HalfWeight, UV0, UV1); } IMPLOT_INLINE bool Render(ImDrawList& draw_list, const ImRect& cull_rect, int prim) const { - ImVec2 p = this->Transformer(Getter(prim)); + ImVec2 p = this->Transformer(Getter[prim]); if (p.x >= cull_rect.Min.x && p.y >= cull_rect.Min.y && p.x <= cull_rect.Max.x && p.y <= cull_rect.Max.y) { for (int i = 0; i < Count; i = i + 2) { ImVec2 p1(p.x + Marker[i].x * Size, p.y + Marker[i].y * Size); @@ -1493,15 +1470,15 @@ struct RendererMarkersLine : RendererBase { mutable ImVec2 UV1; }; -static const ImVec2 MARKER_FILL_CIRCLE[10] = {ImVec2(1.0f, 0.0f), ImVec2(0.809017f, 0.58778524f),ImVec2(0.30901697f, 0.95105654f),ImVec2(-0.30901703f, 0.9510565f),ImVec2(-0.80901706f, 0.5877852f),ImVec2(-1.0f, 0.0f),ImVec2(-0.80901694f, -0.58778536f),ImVec2(-0.3090171f, -0.9510565f),ImVec2(0.30901712f, -0.9510565f),ImVec2(0.80901694f, -0.5877853f)}; -static const ImVec2 MARKER_FILL_SQUARE[4] = {ImVec2(SQRT_1_2,SQRT_1_2), ImVec2(SQRT_1_2,-SQRT_1_2), ImVec2(-SQRT_1_2,-SQRT_1_2), ImVec2(-SQRT_1_2,SQRT_1_2)}; -static const ImVec2 MARKER_FILL_DIAMOND[4] = {ImVec2(1, 0), ImVec2(0, -1), ImVec2(-1, 0), ImVec2(0, 1)}; -static const ImVec2 MARKER_FILL_UP[3] = {ImVec2(SQRT_3_2,0.5f),ImVec2(0,-1),ImVec2(-SQRT_3_2,0.5f)}; -static const ImVec2 MARKER_FILL_DOWN[3] = {ImVec2(SQRT_3_2,-0.5f),ImVec2(0,1),ImVec2(-SQRT_3_2,-0.5f)}; -static const ImVec2 MARKER_FILL_LEFT[3] = {ImVec2(-1,0), ImVec2(0.5, SQRT_3_2), ImVec2(0.5, -SQRT_3_2)}; -static const ImVec2 MARKER_FILL_RIGHT[3] = {ImVec2(1,0), ImVec2(-0.5, SQRT_3_2), ImVec2(-0.5, -SQRT_3_2)}; - -static const ImVec2 MARKER_LINE_CIRCLE[20] = { +constexpr ImVec2 MARKER_FILL_CIRCLE[10] = {ImVec2(1.0f, 0.0f), ImVec2(0.809017f, 0.58778524f),ImVec2(0.30901697f, 0.95105654f),ImVec2(-0.30901703f, 0.9510565f),ImVec2(-0.80901706f, 0.5877852f),ImVec2(-1.0f, 0.0f),ImVec2(-0.80901694f, -0.58778536f),ImVec2(-0.3090171f, -0.9510565f),ImVec2(0.30901712f, -0.9510565f),ImVec2(0.80901694f, -0.5877853f)}; +constexpr ImVec2 MARKER_FILL_SQUARE[4] = {ImVec2(SQRT_1_2,SQRT_1_2), ImVec2(SQRT_1_2,-SQRT_1_2), ImVec2(-SQRT_1_2,-SQRT_1_2), ImVec2(-SQRT_1_2,SQRT_1_2)}; +constexpr ImVec2 MARKER_FILL_DIAMOND[4] = {ImVec2(1, 0), ImVec2(0, -1), ImVec2(-1, 0), ImVec2(0, 1)}; +constexpr ImVec2 MARKER_FILL_UP[3] = {ImVec2(SQRT_3_2,0.5f),ImVec2(0,-1),ImVec2(-SQRT_3_2,0.5f)}; +constexpr ImVec2 MARKER_FILL_DOWN[3] = {ImVec2(SQRT_3_2,-0.5f),ImVec2(0,1),ImVec2(-SQRT_3_2,-0.5f)}; +constexpr ImVec2 MARKER_FILL_LEFT[3] = {ImVec2(-1,0), ImVec2(0.5, SQRT_3_2), ImVec2(0.5, -SQRT_3_2)}; +constexpr ImVec2 MARKER_FILL_RIGHT[3] = {ImVec2(1,0), ImVec2(-0.5, SQRT_3_2), ImVec2(-0.5, -SQRT_3_2)}; + +constexpr ImVec2 MARKER_LINE_CIRCLE[20] = { ImVec2(1.0f, 0.0f), ImVec2(0.809017f, 0.58778524f), ImVec2(0.809017f, 0.58778524f), @@ -1523,15 +1500,15 @@ static const ImVec2 MARKER_LINE_CIRCLE[20] = { ImVec2(0.80901694f, -0.5877853f), ImVec2(1.0f, 0.0f) }; -static const ImVec2 MARKER_LINE_SQUARE[8] = {ImVec2(SQRT_1_2,SQRT_1_2), ImVec2(SQRT_1_2,-SQRT_1_2), ImVec2(SQRT_1_2,-SQRT_1_2), ImVec2(-SQRT_1_2,-SQRT_1_2), ImVec2(-SQRT_1_2,-SQRT_1_2), ImVec2(-SQRT_1_2,SQRT_1_2), ImVec2(-SQRT_1_2,SQRT_1_2), ImVec2(SQRT_1_2,SQRT_1_2)}; -static const ImVec2 MARKER_LINE_DIAMOND[8] = {ImVec2(1, 0), ImVec2(0, -1), ImVec2(0, -1), ImVec2(-1, 0), ImVec2(-1, 0), ImVec2(0, 1), ImVec2(0, 1), ImVec2(1, 0)}; -static const ImVec2 MARKER_LINE_UP[6] = {ImVec2(SQRT_3_2,0.5f), ImVec2(0,-1),ImVec2(0,-1),ImVec2(-SQRT_3_2,0.5f),ImVec2(-SQRT_3_2,0.5f),ImVec2(SQRT_3_2,0.5f)}; -static const ImVec2 MARKER_LINE_DOWN[6] = {ImVec2(SQRT_3_2,-0.5f),ImVec2(0,1),ImVec2(0,1),ImVec2(-SQRT_3_2,-0.5f), ImVec2(-SQRT_3_2,-0.5f), ImVec2(SQRT_3_2,-0.5f)}; -static const ImVec2 MARKER_LINE_LEFT[6] = {ImVec2(-1,0), ImVec2(0.5, SQRT_3_2), ImVec2(0.5, SQRT_3_2), ImVec2(0.5, -SQRT_3_2) , ImVec2(0.5, -SQRT_3_2) , ImVec2(-1,0) }; -static const ImVec2 MARKER_LINE_RIGHT[6] = {ImVec2(1,0), ImVec2(-0.5, SQRT_3_2), ImVec2(-0.5, SQRT_3_2), ImVec2(-0.5, -SQRT_3_2), ImVec2(-0.5, -SQRT_3_2), ImVec2(1,0) }; -static const ImVec2 MARKER_LINE_ASTERISK[6] = {ImVec2(-SQRT_3_2, -0.5f), ImVec2(SQRT_3_2, 0.5f), ImVec2(-SQRT_3_2, 0.5f), ImVec2(SQRT_3_2, -0.5f), ImVec2(0, -1), ImVec2(0, 1)}; -static const ImVec2 MARKER_LINE_PLUS[4] = {ImVec2(-1, 0), ImVec2(1, 0), ImVec2(0, -1), ImVec2(0, 1)}; -static const ImVec2 MARKER_LINE_CROSS[4] = {ImVec2(-SQRT_1_2,-SQRT_1_2),ImVec2(SQRT_1_2,SQRT_1_2),ImVec2(SQRT_1_2,-SQRT_1_2),ImVec2(-SQRT_1_2,SQRT_1_2)}; +constexpr ImVec2 MARKER_LINE_SQUARE[8] = {ImVec2(SQRT_1_2,SQRT_1_2), ImVec2(SQRT_1_2,-SQRT_1_2), ImVec2(SQRT_1_2,-SQRT_1_2), ImVec2(-SQRT_1_2,-SQRT_1_2), ImVec2(-SQRT_1_2,-SQRT_1_2), ImVec2(-SQRT_1_2,SQRT_1_2), ImVec2(-SQRT_1_2,SQRT_1_2), ImVec2(SQRT_1_2,SQRT_1_2)}; +constexpr ImVec2 MARKER_LINE_DIAMOND[8] = {ImVec2(1, 0), ImVec2(0, -1), ImVec2(0, -1), ImVec2(-1, 0), ImVec2(-1, 0), ImVec2(0, 1), ImVec2(0, 1), ImVec2(1, 0)}; +constexpr ImVec2 MARKER_LINE_UP[6] = {ImVec2(SQRT_3_2,0.5f), ImVec2(0,-1),ImVec2(0,-1),ImVec2(-SQRT_3_2,0.5f),ImVec2(-SQRT_3_2,0.5f),ImVec2(SQRT_3_2,0.5f)}; +constexpr ImVec2 MARKER_LINE_DOWN[6] = {ImVec2(SQRT_3_2,-0.5f),ImVec2(0,1),ImVec2(0,1),ImVec2(-SQRT_3_2,-0.5f), ImVec2(-SQRT_3_2,-0.5f), ImVec2(SQRT_3_2,-0.5f)}; +constexpr ImVec2 MARKER_LINE_LEFT[6] = {ImVec2(-1,0), ImVec2(0.5, SQRT_3_2), ImVec2(0.5, SQRT_3_2), ImVec2(0.5, -SQRT_3_2) , ImVec2(0.5, -SQRT_3_2) , ImVec2(-1,0) }; +constexpr ImVec2 MARKER_LINE_RIGHT[6] = {ImVec2(1,0), ImVec2(-0.5, SQRT_3_2), ImVec2(-0.5, SQRT_3_2), ImVec2(-0.5, -SQRT_3_2), ImVec2(-0.5, -SQRT_3_2), ImVec2(1,0) }; +constexpr ImVec2 MARKER_LINE_ASTERISK[6] = {ImVec2(-SQRT_3_2, -0.5f), ImVec2(SQRT_3_2, 0.5f), ImVec2(-SQRT_3_2, 0.5f), ImVec2(SQRT_3_2, -0.5f), ImVec2(0, -1), ImVec2(0, 1)}; +constexpr ImVec2 MARKER_LINE_PLUS[4] = {ImVec2(-1, 0), ImVec2(1, 0), ImVec2(0, -1), ImVec2(0, 1)}; +constexpr ImVec2 MARKER_LINE_CROSS[4] = {ImVec2(-SQRT_1_2,-SQRT_1_2),ImVec2(SQRT_1_2,SQRT_1_2),ImVec2(SQRT_1_2,-SQRT_1_2),ImVec2(-SQRT_1_2,SQRT_1_2)}; template void RenderMarkers(const _Getter& getter, ImPlotMarker marker, float size, bool rend_fill, ImU32 col_fill, bool rend_line, ImU32 col_line, float weight) { @@ -1567,74 +1544,74 @@ void RenderMarkers(const _Getter& getter, ImPlotMarker marker, float size, bool //----------------------------------------------------------------------------- template -void PlotLineEx(const char* label_id, const _Getter& getter, ImPlotLineFlags flags) { - if (BeginItemEx(label_id, Fitter1<_Getter>(getter), flags, ImPlotCol_Line)) { +void PlotLineEx(const char* label_id, const _Getter& getter, const ImPlotSpec& spec) { + if (BeginItemEx(label_id, Fitter1<_Getter>(getter), spec, spec.LineColor, spec.Marker)) { if (getter.Count <= 0) { EndItem(); return; } const ImPlotNextItemData& s = GetItemData(); if (getter.Count > 1) { - if (ImHasFlag(flags, ImPlotLineFlags_Shaded) && s.RenderFill) { - const ImU32 col_fill = ImGui::GetColorU32(s.Colors[ImPlotCol_Fill]); + if (ImHasFlag(spec.Flags, ImPlotLineFlags_Shaded) && s.RenderFill) { + const ImU32 col_fill = ImGui::GetColorU32(s.Spec.FillColor); GetterOverrideY<_Getter> getter2(getter, 0); RenderPrimitives2(getter,getter2,col_fill); } if (s.RenderLine) { - const ImU32 col_line = ImGui::GetColorU32(s.Colors[ImPlotCol_Line]); - if (ImHasFlag(flags,ImPlotLineFlags_Segments)) { - RenderPrimitives1(getter,col_line,s.LineWeight); + const ImU32 col_line = ImGui::GetColorU32(s.Spec.LineColor); + if (ImHasFlag(spec.Flags,ImPlotLineFlags_Segments)) { + RenderPrimitives1(getter,col_line,s.Spec.LineWeight); } - else if (ImHasFlag(flags, ImPlotLineFlags_Loop)) { - if (ImHasFlag(flags, ImPlotLineFlags_SkipNaN)) - RenderPrimitives1(GetterLoop<_Getter>(getter),col_line,s.LineWeight); + else if (ImHasFlag(spec.Flags, ImPlotLineFlags_Loop)) { + if (ImHasFlag(spec.Flags, ImPlotLineFlags_SkipNaN)) + RenderPrimitives1(GetterLoop<_Getter>(getter),col_line,s.Spec.LineWeight); else - RenderPrimitives1(GetterLoop<_Getter>(getter),col_line,s.LineWeight); + RenderPrimitives1(GetterLoop<_Getter>(getter),col_line,s.Spec.LineWeight); } else { - if (ImHasFlag(flags, ImPlotLineFlags_SkipNaN)) - RenderPrimitives1(getter,col_line,s.LineWeight); + if (ImHasFlag(spec.Flags, ImPlotLineFlags_SkipNaN)) + RenderPrimitives1(getter,col_line,s.Spec.LineWeight); else - RenderPrimitives1(getter,col_line,s.LineWeight); + RenderPrimitives1(getter,col_line,s.Spec.LineWeight); } } } // render markers - if (s.Marker != ImPlotMarker_None) { - if (ImHasFlag(flags, ImPlotLineFlags_NoClip)) { + if (s.RenderMarkers) { + if (ImHasFlag(spec.Flags, ImPlotLineFlags_NoClip)) { PopPlotClipRect(); - PushPlotClipRect(s.MarkerSize); + PushPlotClipRect(s.Spec.Size); } - const ImU32 col_line = ImGui::GetColorU32(s.Colors[ImPlotCol_MarkerOutline]); - const ImU32 col_fill = ImGui::GetColorU32(s.Colors[ImPlotCol_MarkerFill]); - RenderMarkers<_Getter>(getter, s.Marker, s.MarkerSize, s.RenderMarkerFill, col_fill, s.RenderMarkerLine, col_line, s.MarkerWeight); + const ImU32 col_line = ImGui::GetColorU32(s.Spec.LineColor); + const ImU32 col_fill = ImGui::GetColorU32(s.Spec.FillColor); + RenderMarkers<_Getter>(getter, s.Spec.Marker, s.Spec.Size, s.RenderFill, col_fill, s.RenderLine, col_line, s.Spec.LineWeight); } EndItem(); } } template -void PlotLine(const char* label_id, const T* values, int count, double xscale, double x0, ImPlotLineFlags flags, int offset, int stride) { - GetterXY> getter(IndexerLin(xscale,x0),IndexerIdx(values,count,offset,stride),count); - PlotLineEx(label_id, getter, flags); +void PlotLine(const char* label_id, const T* values, int count, double xscale, double x0, const ImPlotSpec& spec) { + GetterXY> getter(IndexerLin(xscale,x0),IndexerIdx(values,count,spec.Offset,Stride(spec)),count); + PlotLineEx(label_id, getter, spec); } template -void PlotLine(const char* label_id, const T* xs, const T* ys, int count, ImPlotLineFlags flags, int offset, int stride) { - GetterXY,IndexerIdx> getter(IndexerIdx(xs,count,offset,stride),IndexerIdx(ys,count,offset,stride),count); - PlotLineEx(label_id, getter, flags); +void PlotLine(const char* label_id, const T* xs, const T* ys, int count, const ImPlotSpec& spec) { + GetterXY,IndexerIdx> getter(IndexerIdx(xs,count,spec.Offset,Stride(spec)),IndexerIdx(ys,count,spec.Offset,Stride(spec)),count); + PlotLineEx(label_id, getter, spec); } #define INSTANTIATE_MACRO(T) \ - template IMPLOT_API void PlotLine (const char* label_id, const T* values, int count, double xscale, double x0, ImPlotLineFlags flags, int offset, int stride); \ - template IMPLOT_API void PlotLine(const char* label_id, const T* xs, const T* ys, int count, ImPlotLineFlags flags, int offset, int stride); + template IMPLOT_API void PlotLine (const char* label_id, const T* values, int count, double xscale, double x0, const ImPlotSpec& spec); \ + template IMPLOT_API void PlotLine(const char* label_id, const T* xs, const T* ys, int count, const ImPlotSpec& spec); CALL_INSTANTIATE_FOR_NUMERIC_TYPES() #undef INSTANTIATE_MACRO // custom -void PlotLineG(const char* label_id, ImPlotGetter getter_func, void* data, int count, ImPlotLineFlags flags) { +void PlotLineG(const char* label_id, ImPlotGetter getter_func, void* data, int count, const ImPlotSpec& spec) { GetterFuncPtr getter(getter_func,data, count); - PlotLineEx(label_id, getter, flags); + PlotLineEx(label_id, getter, spec); } //----------------------------------------------------------------------------- @@ -1642,49 +1619,50 @@ void PlotLineG(const char* label_id, ImPlotGetter getter_func, void* data, int c //----------------------------------------------------------------------------- template -void PlotScatterEx(const char* label_id, const Getter& getter, ImPlotScatterFlags flags) { - if (BeginItemEx(label_id, Fitter1(getter), flags, ImPlotCol_MarkerOutline)) { +void PlotScatterEx(const char* label_id, const Getter& getter, const ImPlotSpec& spec) { + // force scatter to render a marker even if none + ImPlotMarker marker = spec.Marker == ImPlotMarker_None ? ImPlotMarker_Auto: spec.Marker; + if (BeginItemEx(label_id, Fitter1(getter), spec, spec.LineColor, marker)) { if (getter.Count <= 0) { EndItem(); return; } const ImPlotNextItemData& s = GetItemData(); - ImPlotMarker marker = s.Marker == ImPlotMarker_None ? ImPlotMarker_Circle: s.Marker; - if (marker != ImPlotMarker_None) { - if (ImHasFlag(flags,ImPlotScatterFlags_NoClip)) { + if (s.RenderMarkers) { + if (ImHasFlag(spec.Flags,ImPlotScatterFlags_NoClip)) { PopPlotClipRect(); - PushPlotClipRect(s.MarkerSize); + PushPlotClipRect(s.Spec.Size); } - const ImU32 col_line = ImGui::GetColorU32(s.Colors[ImPlotCol_MarkerOutline]); - const ImU32 col_fill = ImGui::GetColorU32(s.Colors[ImPlotCol_MarkerFill]); - RenderMarkers(getter, marker, s.MarkerSize, s.RenderMarkerFill, col_fill, s.RenderMarkerLine, col_line, s.MarkerWeight); + const ImU32 col_line = ImGui::GetColorU32(s.Spec.LineColor); + const ImU32 col_fill = ImGui::GetColorU32(s.Spec.FillColor); + RenderMarkers(getter, s.Spec.Marker, s.Spec.Size, s.RenderFill, col_fill, s.RenderLine, col_line, s.Spec.LineWeight); } EndItem(); } } template -void PlotScatter(const char* label_id, const T* values, int count, double xscale, double x0, ImPlotScatterFlags flags, int offset, int stride) { - GetterXY> getter(IndexerLin(xscale,x0),IndexerIdx(values,count,offset,stride),count); - PlotScatterEx(label_id, getter, flags); +void PlotScatter(const char* label_id, const T* values, int count, double xscale, double x0, const ImPlotSpec& spec) { + GetterXY> getter(IndexerLin(xscale,x0),IndexerIdx(values,count,spec.Offset, Stride(spec)),count); + PlotScatterEx(label_id, getter, spec); } template -void PlotScatter(const char* label_id, const T* xs, const T* ys, int count, ImPlotScatterFlags flags, int offset, int stride) { - GetterXY,IndexerIdx> getter(IndexerIdx(xs,count,offset,stride),IndexerIdx(ys,count,offset,stride),count); - return PlotScatterEx(label_id, getter, flags); +void PlotScatter(const char* label_id, const T* xs, const T* ys, int count, const ImPlotSpec& spec) { + GetterXY,IndexerIdx> getter(IndexerIdx(xs,count,spec.Offset, Stride(spec)),IndexerIdx(ys,count,spec.Offset, Stride(spec)),count); + return PlotScatterEx(label_id, getter, spec); } #define INSTANTIATE_MACRO(T) \ - template IMPLOT_API void PlotScatter(const char* label_id, const T* values, int count, double xscale, double x0, ImPlotScatterFlags flags, int offset, int stride); \ - template IMPLOT_API void PlotScatter(const char* label_id, const T* xs, const T* ys, int count, ImPlotScatterFlags flags, int offset, int stride); + template IMPLOT_API void PlotScatter(const char* label_id, const T* values, int count, double xscale, double x0, const ImPlotSpec& spec); \ + template IMPLOT_API void PlotScatter(const char* label_id, const T* xs, const T* ys, int count, const ImPlotSpec& spec); CALL_INSTANTIATE_FOR_NUMERIC_TYPES() #undef INSTANTIATE_MACRO // custom -void PlotScatterG(const char* label_id, ImPlotGetter getter_func, void* data, int count, ImPlotScatterFlags flags) { +void PlotScatterG(const char* label_id, ImPlotGetter getter_func, void* data, int count, const ImPlotSpec& spec) { GetterFuncPtr getter(getter_func,data, count); - return PlotScatterEx(label_id, getter, flags); + return PlotScatterEx(label_id, getter, spec); } //----------------------------------------------------------------------------- @@ -1692,63 +1670,63 @@ void PlotScatterG(const char* label_id, ImPlotGetter getter_func, void* data, in //----------------------------------------------------------------------------- template -void PlotStairsEx(const char* label_id, const Getter& getter, ImPlotStairsFlags flags) { - if (BeginItemEx(label_id, Fitter1(getter), flags, ImPlotCol_Line)) { +void PlotStairsEx(const char* label_id, const Getter& getter, const ImPlotSpec& spec) { + if (BeginItemEx(label_id, Fitter1(getter), spec, spec.LineColor, spec.Marker)) { if (getter.Count <= 0) { EndItem(); return; } const ImPlotNextItemData& s = GetItemData(); if (getter.Count > 1) { - if (s.RenderFill && ImHasFlag(flags,ImPlotStairsFlags_Shaded)) { - const ImU32 col_fill = ImGui::GetColorU32(s.Colors[ImPlotCol_Fill]); - if (ImHasFlag(flags, ImPlotStairsFlags_PreStep)) + if (s.RenderFill && ImHasFlag(spec.Flags,ImPlotStairsFlags_Shaded)) { + const ImU32 col_fill = ImGui::GetColorU32(s.Spec.FillColor); + if (ImHasFlag(spec.Flags, ImPlotStairsFlags_PreStep)) RenderPrimitives1(getter,col_fill); else RenderPrimitives1(getter,col_fill); } if (s.RenderLine) { - const ImU32 col_line = ImGui::GetColorU32(s.Colors[ImPlotCol_Line]); - if (ImHasFlag(flags, ImPlotStairsFlags_PreStep)) - RenderPrimitives1(getter,col_line,s.LineWeight); + const ImU32 col_line = ImGui::GetColorU32(s.Spec.LineColor); + if (ImHasFlag(spec.Flags, ImPlotStairsFlags_PreStep)) + RenderPrimitives1(getter,col_line,s.Spec.LineWeight); else - RenderPrimitives1(getter,col_line,s.LineWeight); + RenderPrimitives1(getter,col_line,s.Spec.LineWeight); } } // render markers - if (s.Marker != ImPlotMarker_None) { + if (s.RenderMarkers) { PopPlotClipRect(); - PushPlotClipRect(s.MarkerSize); - const ImU32 col_line = ImGui::GetColorU32(s.Colors[ImPlotCol_MarkerOutline]); - const ImU32 col_fill = ImGui::GetColorU32(s.Colors[ImPlotCol_MarkerFill]); - RenderMarkers(getter, s.Marker, s.MarkerSize, s.RenderMarkerFill, col_fill, s.RenderMarkerLine, col_line, s.MarkerWeight); + PushPlotClipRect(s.Spec.Size); + const ImU32 col_line = ImGui::GetColorU32(s.Spec.LineColor); + const ImU32 col_fill = ImGui::GetColorU32(s.Spec.FillColor); + RenderMarkers(getter, s.Spec.Marker, s.Spec.Size, s.RenderFill, col_fill, s.RenderLine, col_line, s.Spec.LineWeight); } EndItem(); } } template -void PlotStairs(const char* label_id, const T* values, int count, double xscale, double x0, ImPlotStairsFlags flags, int offset, int stride) { - GetterXY> getter(IndexerLin(xscale,x0),IndexerIdx(values,count,offset,stride),count); - PlotStairsEx(label_id, getter, flags); +void PlotStairs(const char* label_id, const T* values, int count, double xscale, double x0, const ImPlotSpec& spec) { + GetterXY> getter(IndexerLin(xscale,x0),IndexerIdx(values,count,spec.Offset,Stride(spec)),count); + PlotStairsEx(label_id, getter, spec); } template -void PlotStairs(const char* label_id, const T* xs, const T* ys, int count, ImPlotStairsFlags flags, int offset, int stride) { - GetterXY,IndexerIdx> getter(IndexerIdx(xs,count,offset,stride),IndexerIdx(ys,count,offset,stride),count); - return PlotStairsEx(label_id, getter, flags); +void PlotStairs(const char* label_id, const T* xs, const T* ys, int count, const ImPlotSpec& spec) { + GetterXY,IndexerIdx> getter(IndexerIdx(xs,count,spec.Offset,Stride(spec)),IndexerIdx(ys,count,spec.Offset,Stride(spec)),count); + return PlotStairsEx(label_id, getter, spec); } #define INSTANTIATE_MACRO(T) \ - template IMPLOT_API void PlotStairs (const char* label_id, const T* values, int count, double xscale, double x0, ImPlotStairsFlags flags, int offset, int stride); \ - template IMPLOT_API void PlotStairs(const char* label_id, const T* xs, const T* ys, int count, ImPlotStairsFlags flags, int offset, int stride); + template IMPLOT_API void PlotStairs (const char* label_id, const T* values, int count, double xscale, double x0, const ImPlotSpec& spec); \ + template IMPLOT_API void PlotStairs(const char* label_id, const T* xs, const T* ys, int count, const ImPlotSpec& spec); CALL_INSTANTIATE_FOR_NUMERIC_TYPES() #undef INSTANTIATE_MACRO // custom -void PlotStairsG(const char* label_id, ImPlotGetter getter_func, void* data, int count, ImPlotStairsFlags flags) { +void PlotStairsG(const char* label_id, ImPlotGetter getter_func, void* data, int count, const ImPlotSpec& spec) { GetterFuncPtr getter(getter_func,data, count); - return PlotStairsEx(label_id, getter, flags); + return PlotStairsEx(label_id, getter, spec); } //----------------------------------------------------------------------------- @@ -1756,15 +1734,15 @@ void PlotStairsG(const char* label_id, ImPlotGetter getter_func, void* data, int //----------------------------------------------------------------------------- template -void PlotShadedEx(const char* label_id, const Getter1& getter1, const Getter2& getter2, ImPlotShadedFlags flags) { - if (BeginItemEx(label_id, Fitter2(getter1,getter2), flags, ImPlotCol_Fill)) { +void PlotShadedEx(const char* label_id, const Getter1& getter1, const Getter2& getter2, const ImPlotSpec& spec) { + if (BeginItemEx(label_id, Fitter2(getter1,getter2), spec, spec.FillColor)) { if (getter1.Count <= 0 || getter2.Count <= 0) { EndItem(); return; } const ImPlotNextItemData& s = GetItemData(); if (s.RenderFill) { - const ImU32 col = ImGui::GetColorU32(s.Colors[ImPlotCol_Fill]); + const ImU32 col = ImGui::GetColorU32(s.Spec.FillColor); RenderPrimitives2(getter1,getter2,col); } EndItem(); @@ -1772,47 +1750,47 @@ void PlotShadedEx(const char* label_id, const Getter1& getter1, const Getter2& g } template -void PlotShaded(const char* label_id, const T* values, int count, double y_ref, double xscale, double x0, ImPlotShadedFlags flags, int offset, int stride) { +void PlotShaded(const char* label_id, const T* values, int count, double y_ref, double xscale, double x0, const ImPlotSpec& spec) { if (!(y_ref > -DBL_MAX)) y_ref = GetPlotLimits(IMPLOT_AUTO,IMPLOT_AUTO).Y.Min; if (!(y_ref < DBL_MAX)) y_ref = GetPlotLimits(IMPLOT_AUTO,IMPLOT_AUTO).Y.Max; - GetterXY> getter1(IndexerLin(xscale,x0),IndexerIdx(values,count,offset,stride),count); + GetterXY> getter1(IndexerLin(xscale,x0),IndexerIdx(values,count,spec.Offset,Stride(spec)),count); GetterXY getter2(IndexerLin(xscale,x0),IndexerConst(y_ref),count); - PlotShadedEx(label_id, getter1, getter2, flags); + PlotShadedEx(label_id, getter1, getter2, spec); } template -void PlotShaded(const char* label_id, const T* xs, const T* ys, int count, double y_ref, ImPlotShadedFlags flags, int offset, int stride) { +void PlotShaded(const char* label_id, const T* xs, const T* ys, int count, double y_ref, const ImPlotSpec& spec) { if (y_ref == -HUGE_VAL) y_ref = GetPlotLimits(IMPLOT_AUTO,IMPLOT_AUTO).Y.Min; if (y_ref == HUGE_VAL) y_ref = GetPlotLimits(IMPLOT_AUTO,IMPLOT_AUTO).Y.Max; - GetterXY,IndexerIdx> getter1(IndexerIdx(xs,count,offset,stride),IndexerIdx(ys,count,offset,stride),count); - GetterXY,IndexerConst> getter2(IndexerIdx(xs,count,offset,stride),IndexerConst(y_ref),count); - PlotShadedEx(label_id, getter1, getter2, flags); + GetterXY,IndexerIdx> getter1(IndexerIdx(xs,count,spec.Offset,Stride(spec)),IndexerIdx(ys,count,spec.Offset,Stride(spec)),count); + GetterXY,IndexerConst> getter2(IndexerIdx(xs,count,spec.Offset,Stride(spec)),IndexerConst(y_ref),count); + PlotShadedEx(label_id, getter1, getter2, spec); } template -void PlotShaded(const char* label_id, const T* xs, const T* ys1, const T* ys2, int count, ImPlotShadedFlags flags, int offset, int stride) { - GetterXY,IndexerIdx> getter1(IndexerIdx(xs,count,offset,stride),IndexerIdx(ys1,count,offset,stride),count); - GetterXY,IndexerIdx> getter2(IndexerIdx(xs,count,offset,stride),IndexerIdx(ys2,count,offset,stride),count); - PlotShadedEx(label_id, getter1, getter2, flags); +void PlotShaded(const char* label_id, const T* xs, const T* ys1, const T* ys2, int count, const ImPlotSpec& spec) { + GetterXY,IndexerIdx> getter1(IndexerIdx(xs,count,spec.Offset,Stride(spec)),IndexerIdx(ys1,count,spec.Offset,Stride(spec)),count); + GetterXY,IndexerIdx> getter2(IndexerIdx(xs,count,spec.Offset,Stride(spec)),IndexerIdx(ys2,count,spec.Offset,Stride(spec)),count); + PlotShadedEx(label_id, getter1, getter2, spec); } #define INSTANTIATE_MACRO(T) \ - template IMPLOT_API void PlotShaded(const char* label_id, const T* values, int count, double y_ref, double xscale, double x0, ImPlotShadedFlags flags, int offset, int stride); \ - template IMPLOT_API void PlotShaded(const char* label_id, const T* xs, const T* ys, int count, double y_ref, ImPlotShadedFlags flags, int offset, int stride); \ - template IMPLOT_API void PlotShaded(const char* label_id, const T* xs, const T* ys1, const T* ys2, int count, ImPlotShadedFlags flags, int offset, int stride); + template IMPLOT_API void PlotShaded(const char* label_id, const T* values, int count, double y_ref, double xscale, double x0, const ImPlotSpec& spec); \ + template IMPLOT_API void PlotShaded(const char* label_id, const T* xs, const T* ys, int count, double y_ref, const ImPlotSpec& spec); \ + template IMPLOT_API void PlotShaded(const char* label_id, const T* xs, const T* ys1, const T* ys2, int count, const ImPlotSpec& spec); CALL_INSTANTIATE_FOR_NUMERIC_TYPES() #undef INSTANTIATE_MACRO // custom -void PlotShadedG(const char* label_id, ImPlotGetter getter_func1, void* data1, ImPlotGetter getter_func2, void* data2, int count, ImPlotShadedFlags flags) { +void PlotShadedG(const char* label_id, ImPlotGetter getter_func1, void* data1, ImPlotGetter getter_func2, void* data2, int count, const ImPlotSpec& spec) { GetterFuncPtr getter1(getter_func1, data1, count); GetterFuncPtr getter2(getter_func2, data2, count); - PlotShadedEx(label_id, getter1, getter2, flags); + PlotShadedEx(label_id, getter1, getter2, spec); } //----------------------------------------------------------------------------- @@ -1820,15 +1798,15 @@ void PlotShadedG(const char* label_id, ImPlotGetter getter_func1, void* data1, I //----------------------------------------------------------------------------- template -void PlotBarsVEx(const char* label_id, const Getter1& getter1, const Getter2 getter2, double width, ImPlotBarsFlags flags) { - if (BeginItemEx(label_id, FitterBarV(getter1,getter2,width), flags, ImPlotCol_Fill)) { +void PlotBarsVEx(const char* label_id, const Getter1& getter1, const Getter2 getter2, double width, const ImPlotSpec& spec) { + if (BeginItemEx(label_id, FitterBarV(getter1,getter2,width), spec, spec.FillColor)) { if (getter1.Count <= 0 || getter2.Count <= 0) { EndItem(); return; } const ImPlotNextItemData& s = GetItemData(); - const ImU32 col_fill = ImGui::GetColorU32(s.Colors[ImPlotCol_Fill]); - const ImU32 col_line = ImGui::GetColorU32(s.Colors[ImPlotCol_Line]); + const ImU32 col_fill = ImGui::GetColorU32(s.Spec.FillColor); + const ImU32 col_line = ImGui::GetColorU32(s.Spec.LineColor); bool rend_fill = s.RenderFill; bool rend_line = s.RenderLine; if (rend_fill) { @@ -1837,22 +1815,22 @@ void PlotBarsVEx(const char* label_id, const Getter1& getter1, const Getter2 get rend_line = false; } if (rend_line) { - RenderPrimitives2(getter1,getter2,col_line,width,s.LineWeight); + RenderPrimitives2(getter1,getter2,col_line,width,s.Spec.LineWeight); } EndItem(); } } template -void PlotBarsHEx(const char* label_id, const Getter1& getter1, const Getter2& getter2, double height, ImPlotBarsFlags flags) { - if (BeginItemEx(label_id, FitterBarH(getter1,getter2,height), flags, ImPlotCol_Fill)) { +void PlotBarsHEx(const char* label_id, const Getter1& getter1, const Getter2& getter2, double height, const ImPlotSpec& spec) { + if (BeginItemEx(label_id, FitterBarH(getter1,getter2,height), spec, spec.FillColor)) { if (getter1.Count <= 0 || getter2.Count <= 0) { EndItem(); return; } const ImPlotNextItemData& s = GetItemData(); - const ImU32 col_fill = ImGui::GetColorU32(s.Colors[ImPlotCol_Fill]); - const ImU32 col_line = ImGui::GetColorU32(s.Colors[ImPlotCol_Line]); + const ImU32 col_fill = ImGui::GetColorU32(s.Spec.FillColor); + const ImU32 col_line = ImGui::GetColorU32(s.Spec.LineColor); bool rend_fill = s.RenderFill; bool rend_line = s.RenderLine; if (rend_fill) { @@ -1861,56 +1839,56 @@ void PlotBarsHEx(const char* label_id, const Getter1& getter1, const Getter2& ge rend_line = false; } if (rend_line) { - RenderPrimitives2(getter1,getter2,col_line,height,s.LineWeight); + RenderPrimitives2(getter1,getter2,col_line,height,s.Spec.LineWeight); } EndItem(); } } template -void PlotBars(const char* label_id, const T* values, int count, double bar_size, double shift, ImPlotBarsFlags flags, int offset, int stride) { - if (ImHasFlag(flags, ImPlotBarsFlags_Horizontal)) { - GetterXY,IndexerLin> getter1(IndexerIdx(values,count,offset,stride),IndexerLin(1.0,shift),count); +void PlotBars(const char* label_id, const T* values, int count, double bar_size, double shift, const ImPlotSpec& spec) { + if (ImHasFlag(spec.Flags, ImPlotBarsFlags_Horizontal)) { + GetterXY,IndexerLin> getter1(IndexerIdx(values,count,spec.Offset,Stride(spec)),IndexerLin(1.0,shift),count); GetterXY getter2(IndexerConst(0),IndexerLin(1.0,shift),count); - PlotBarsHEx(label_id, getter1, getter2, bar_size, flags); + PlotBarsHEx(label_id, getter1, getter2, bar_size, spec); } else { - GetterXY> getter1(IndexerLin(1.0,shift),IndexerIdx(values,count,offset,stride),count); + GetterXY> getter1(IndexerLin(1.0,shift),IndexerIdx(values,count,spec.Offset,Stride(spec)),count); GetterXY getter2(IndexerLin(1.0,shift),IndexerConst(0),count); - PlotBarsVEx(label_id, getter1, getter2, bar_size, flags); + PlotBarsVEx(label_id, getter1, getter2, bar_size, spec); } } template -void PlotBars(const char* label_id, const T* xs, const T* ys, int count, double bar_size, ImPlotBarsFlags flags, int offset, int stride) { - if (ImHasFlag(flags, ImPlotBarsFlags_Horizontal)) { - GetterXY,IndexerIdx> getter1(IndexerIdx(xs,count,offset,stride),IndexerIdx(ys,count,offset,stride),count); - GetterXY> getter2(IndexerConst(0),IndexerIdx(ys,count,offset,stride),count); - PlotBarsHEx(label_id, getter1, getter2, bar_size, flags); +void PlotBars(const char* label_id, const T* xs, const T* ys, int count, double bar_size, const ImPlotSpec& spec) { + if (ImHasFlag(spec.Flags, ImPlotBarsFlags_Horizontal)) { + GetterXY,IndexerIdx> getter1(IndexerIdx(xs,count,spec.Offset,Stride(spec)),IndexerIdx(ys,count,spec.Offset,Stride(spec)),count); + GetterXY> getter2(IndexerConst(0),IndexerIdx(ys,count,spec.Offset,Stride(spec)),count); + PlotBarsHEx(label_id, getter1, getter2, bar_size, spec); } else { - GetterXY,IndexerIdx> getter1(IndexerIdx(xs,count,offset,stride),IndexerIdx(ys,count,offset,stride),count); - GetterXY,IndexerConst> getter2(IndexerIdx(xs,count,offset,stride),IndexerConst(0),count); - PlotBarsVEx(label_id, getter1, getter2, bar_size, flags); + GetterXY,IndexerIdx> getter1(IndexerIdx(xs,count,spec.Offset,Stride(spec)),IndexerIdx(ys,count,spec.Offset,Stride(spec)),count); + GetterXY,IndexerConst> getter2(IndexerIdx(xs,count,spec.Offset,Stride(spec)),IndexerConst(0),count); + PlotBarsVEx(label_id, getter1, getter2, bar_size, spec); } } #define INSTANTIATE_MACRO(T) \ - template IMPLOT_API void PlotBars(const char* label_id, const T* values, int count, double bar_size, double shift, ImPlotBarsFlags flags, int offset, int stride); \ - template IMPLOT_API void PlotBars(const char* label_id, const T* xs, const T* ys, int count, double bar_size, ImPlotBarsFlags flags, int offset, int stride); + template IMPLOT_API void PlotBars(const char* label_id, const T* values, int count, double bar_size, double shift, const ImPlotSpec& spec); \ + template IMPLOT_API void PlotBars(const char* label_id, const T* xs, const T* ys, int count, double bar_size, const ImPlotSpec& spec); CALL_INSTANTIATE_FOR_NUMERIC_TYPES() #undef INSTANTIATE_MACRO -void PlotBarsG(const char* label_id, ImPlotGetter getter_func, void* data, int count, double bar_size, ImPlotBarsFlags flags) { - if (ImHasFlag(flags, ImPlotBarsFlags_Horizontal)) { +void PlotBarsG(const char* label_id, ImPlotGetter getter_func, void* data, int count, double bar_size, const ImPlotSpec& spec) { + if (ImHasFlag(spec.Flags, ImPlotBarsFlags_Horizontal)) { GetterFuncPtr getter1(getter_func, data, count); GetterOverrideX getter2(getter1,0); - PlotBarsHEx(label_id, getter1, getter2, bar_size, flags); + PlotBarsHEx(label_id, getter1, getter2, bar_size, spec); } else { GetterFuncPtr getter1(getter_func, data, count); GetterOverrideY getter2(getter1,0); - PlotBarsVEx(label_id, getter1, getter2, bar_size, flags); + PlotBarsVEx(label_id, getter1, getter2, bar_size, spec); } } @@ -1919,9 +1897,12 @@ void PlotBarsG(const char* label_id, ImPlotGetter getter_func, void* data, int c //----------------------------------------------------------------------------- template -void PlotBarGroups(const char* const label_ids[], const T* values, int item_count, int group_count, double group_size, double shift, ImPlotBarGroupsFlags flags) { - const bool horz = ImHasFlag(flags, ImPlotBarGroupsFlags_Horizontal); - const bool stack = ImHasFlag(flags, ImPlotBarGroupsFlags_Stacked); +void PlotBarGroups(const char* const label_ids[], const T* values, int item_count, int group_count, double group_size, double shift, const ImPlotSpec& spec) { + IndexerIdx indexer(values,item_count*group_count,spec.Offset,Stride(spec)); + const bool horz = ImHasFlag(spec.Flags, ImPlotBarGroupsFlags_Horizontal); + const bool stack = ImHasFlag(spec.Flags, ImPlotBarGroupsFlags_Stacked); + ImPlotSpec spec_bars = spec; + spec_bars.Flags = 0; if (stack) { SetupLock(); ImPlotContext& gp = *GImPlot; @@ -1937,7 +1918,7 @@ void PlotBarGroups(const char* const label_ids[], const T* values, int item_coun for (int i = 0; i < item_count; ++i) { if (!IsItemHidden(label_ids[i])) { for (int g = 0; g < group_count; ++g) { - double v = (double)values[i*group_count+g]; + double v = indexer[i*group_count+g]; if (v > 0) { curr_min[g] = pos[g]; curr_max[g] = curr_min[g] + v; @@ -1952,14 +1933,14 @@ void PlotBarGroups(const char* const label_ids[], const T* values, int item_coun } GetterXY,IndexerLin> getter1(IndexerIdx(curr_min,group_count),IndexerLin(1.0,shift),group_count); GetterXY,IndexerLin> getter2(IndexerIdx(curr_max,group_count),IndexerLin(1.0,shift),group_count); - PlotBarsHEx(label_ids[i],getter1,getter2,group_size,0); + PlotBarsHEx(label_ids[i],getter1,getter2,group_size,spec_bars); } } else { for (int i = 0; i < item_count; ++i) { if (!IsItemHidden(label_ids[i])) { for (int g = 0; g < group_count; ++g) { - double v = (double)values[i*group_count+g]; + double v = indexer[i*group_count+g]; if (v > 0) { curr_min[g] = pos[g]; curr_max[g] = curr_min[g] + v; @@ -1974,28 +1955,29 @@ void PlotBarGroups(const char* const label_ids[], const T* values, int item_coun } GetterXY> getter1(IndexerLin(1.0,shift),IndexerIdx(curr_min,group_count),group_count); GetterXY> getter2(IndexerLin(1.0,shift),IndexerIdx(curr_max,group_count),group_count); - PlotBarsVEx(label_ids[i],getter1,getter2,group_size,0); + PlotBarsVEx(label_ids[i],getter1,getter2,group_size,spec_bars); } } } else { const double subsize = group_size / item_count; if (horz) { + spec_bars.Flags = ImPlotBarsFlags_Horizontal; for (int i = 0; i < item_count; ++i) { const double subshift = (i+0.5)*subsize - group_size/2; - PlotBars(label_ids[i],&values[i*group_count],group_count,subsize,subshift+shift,ImPlotBarsFlags_Horizontal); + PlotBars(label_ids[i],&values[i*group_count],group_count,subsize,subshift+shift,spec_bars); } } else { for (int i = 0; i < item_count; ++i) { const double subshift = (i+0.5)*subsize - group_size/2; - PlotBars(label_ids[i],&values[i*group_count],group_count,subsize,subshift+shift); + PlotBars(label_ids[i],&values[i*group_count],group_count,subsize,subshift+shift,spec_bars); } } } } -#define INSTANTIATE_MACRO(T) template IMPLOT_API void PlotBarGroups(const char* const label_ids[], const T* values, int items, int groups, double width, double shift, ImPlotBarGroupsFlags flags); +#define INSTANTIATE_MACRO(T) template IMPLOT_API void PlotBarGroups(const char* const label_ids[], const T* values, int items, int groups, double width, double shift, const ImPlotSpec& spec); CALL_INSTANTIATE_FOR_NUMERIC_TYPES() #undef INSTANTIATE_MACRO @@ -2004,24 +1986,24 @@ CALL_INSTANTIATE_FOR_NUMERIC_TYPES() //----------------------------------------------------------------------------- template -void PlotErrorBarsVEx(const char* label_id, const _GetterPos& getter_pos, const _GetterNeg& getter_neg, ImPlotErrorBarsFlags flags) { - if (BeginItemEx(label_id, Fitter2<_GetterPos,_GetterNeg>(getter_pos, getter_neg), flags, IMPLOT_AUTO)) { +void PlotErrorBarsVEx(const char* label_id, const _GetterPos& getter_pos, const _GetterNeg& getter_neg, const ImPlotSpec& spec) { + if (BeginItemEx(label_id, Fitter2<_GetterPos,_GetterNeg>(getter_pos, getter_neg), spec, IMPLOT_AUTO_COL)) { if (getter_pos.Count <= 0 || getter_neg.Count <= 0) { EndItem(); return; } const ImPlotNextItemData& s = GetItemData(); ImDrawList& draw_list = *GetPlotDrawList(); - const ImU32 col = ImGui::GetColorU32(s.Colors[ImPlotCol_ErrorBar]); - const bool rend_whisker = s.ErrorBarSize > 0; - const float half_whisker = s.ErrorBarSize * 0.5f; + const ImU32 col = ImGui::GetColorU32( IsColorAuto(spec.LineColor) ? ImGui::GetStyleColorVec4(ImGuiCol_Text) : s.Spec.LineColor ); + const bool rend_whisker = s.Spec.Size > 0; + const float half_whisker = s.Spec.Size * 0.5f; for (int i = 0; i < getter_pos.Count; ++i) { - ImVec2 p1 = PlotToPixels(getter_neg(i),IMPLOT_AUTO,IMPLOT_AUTO); - ImVec2 p2 = PlotToPixels(getter_pos(i),IMPLOT_AUTO,IMPLOT_AUTO); - draw_list.AddLine(p1,p2,col, s.ErrorBarWeight); + ImVec2 p1 = PlotToPixels(getter_neg[i],IMPLOT_AUTO,IMPLOT_AUTO); + ImVec2 p2 = PlotToPixels(getter_pos[i],IMPLOT_AUTO,IMPLOT_AUTO); + draw_list.AddLine(p1,p2,col, s.Spec.LineWeight); if (rend_whisker) { - draw_list.AddLine(p1 - ImVec2(half_whisker, 0), p1 + ImVec2(half_whisker, 0), col, s.ErrorBarWeight); - draw_list.AddLine(p2 - ImVec2(half_whisker, 0), p2 + ImVec2(half_whisker, 0), col, s.ErrorBarWeight); + draw_list.AddLine(p1 - ImVec2(half_whisker, 0), p1 + ImVec2(half_whisker, 0), col, s.Spec.LineWeight); + draw_list.AddLine(p2 - ImVec2(half_whisker, 0), p2 + ImVec2(half_whisker, 0), col, s.Spec.LineWeight); } } EndItem(); @@ -2029,24 +2011,24 @@ void PlotErrorBarsVEx(const char* label_id, const _GetterPos& getter_pos, const } template -void PlotErrorBarsHEx(const char* label_id, const _GetterPos& getter_pos, const _GetterNeg& getter_neg, ImPlotErrorBarsFlags flags) { - if (BeginItemEx(label_id, Fitter2<_GetterPos,_GetterNeg>(getter_pos, getter_neg), flags, IMPLOT_AUTO)) { +void PlotErrorBarsHEx(const char* label_id, const _GetterPos& getter_pos, const _GetterNeg& getter_neg, const ImPlotSpec& spec) { + if (BeginItemEx(label_id, Fitter2<_GetterPos,_GetterNeg>(getter_pos, getter_neg), spec, IMPLOT_AUTO_COL)) { if (getter_pos.Count <= 0 || getter_neg.Count <= 0) { EndItem(); return; } const ImPlotNextItemData& s = GetItemData(); ImDrawList& draw_list = *GetPlotDrawList(); - const ImU32 col = ImGui::GetColorU32(s.Colors[ImPlotCol_ErrorBar]); - const bool rend_whisker = s.ErrorBarSize > 0; - const float half_whisker = s.ErrorBarSize * 0.5f; + const ImU32 col = ImGui::GetColorU32( IsColorAuto(spec.LineColor) ? ImGui::GetStyleColorVec4(ImGuiCol_Text) : s.Spec.LineColor ); + const bool rend_whisker = s.Spec.Size > 0; + const float half_whisker = s.Spec.Size * 0.5f; for (int i = 0; i < getter_pos.Count; ++i) { - ImVec2 p1 = PlotToPixels(getter_neg(i),IMPLOT_AUTO,IMPLOT_AUTO); - ImVec2 p2 = PlotToPixels(getter_pos(i),IMPLOT_AUTO,IMPLOT_AUTO); - draw_list.AddLine(p1, p2, col, s.ErrorBarWeight); + ImVec2 p1 = PlotToPixels(getter_neg[i],IMPLOT_AUTO,IMPLOT_AUTO); + ImVec2 p2 = PlotToPixels(getter_pos[i],IMPLOT_AUTO,IMPLOT_AUTO); + draw_list.AddLine(p1, p2, col, s.Spec.LineWeight); if (rend_whisker) { - draw_list.AddLine(p1 - ImVec2(0, half_whisker), p1 + ImVec2(0, half_whisker), col, s.ErrorBarWeight); - draw_list.AddLine(p2 - ImVec2(0, half_whisker), p2 + ImVec2(0, half_whisker), col, s.ErrorBarWeight); + draw_list.AddLine(p1 - ImVec2(0, half_whisker), p1 + ImVec2(0, half_whisker), col, s.Spec.LineWeight); + draw_list.AddLine(p2 - ImVec2(0, half_whisker), p2 + ImVec2(0, half_whisker), col, s.Spec.LineWeight); } } EndItem(); @@ -2054,36 +2036,36 @@ void PlotErrorBarsHEx(const char* label_id, const _GetterPos& getter_pos, const } template -void PlotErrorBars(const char* label_id, const T* xs, const T* ys, const T* err, int count, ImPlotErrorBarsFlags flags, int offset, int stride) { - PlotErrorBars(label_id, xs, ys, err, err, count, flags, offset, stride); +void PlotErrorBars(const char* label_id, const T* xs, const T* ys, const T* err, int count, const ImPlotSpec& spec) { + PlotErrorBars(label_id, xs, ys, err, err, count, spec); } template -void PlotErrorBars(const char* label_id, const T* xs, const T* ys, const T* neg, const T* pos, int count, ImPlotErrorBarsFlags flags, int offset, int stride) { - IndexerIdx indexer_x(xs, count,offset,stride); - IndexerIdx indexer_y(ys, count,offset,stride); - IndexerIdx indexer_n(neg,count,offset,stride); - IndexerIdx indexer_p(pos,count,offset,stride); - GetterError getter(xs, ys, neg, pos, count, offset, stride); - if (ImHasFlag(flags, ImPlotErrorBarsFlags_Horizontal)) { +void PlotErrorBars(const char* label_id, const T* xs, const T* ys, const T* neg, const T* pos, int count, const ImPlotSpec& spec) { + IndexerIdx indexer_x(xs, count,spec.Offset,Stride(spec)); + IndexerIdx indexer_y(ys, count,spec.Offset,Stride(spec)); + IndexerIdx indexer_n(neg,count,spec.Offset,Stride(spec)); + IndexerIdx indexer_p(pos,count,spec.Offset,Stride(spec)); + GetterError getter(xs, ys, neg, pos, count, spec.Offset, Stride(spec)); + if (ImHasFlag(spec.Flags, ImPlotErrorBarsFlags_Horizontal)) { IndexerAdd,IndexerIdx> indexer_xp(indexer_x, indexer_p, 1, 1); IndexerAdd,IndexerIdx> indexer_xn(indexer_x, indexer_n, 1, -1); GetterXY,IndexerIdx>,IndexerIdx> getter_p(indexer_xp, indexer_y, count); GetterXY,IndexerIdx>,IndexerIdx> getter_n(indexer_xn, indexer_y, count); - PlotErrorBarsHEx(label_id, getter_p, getter_n, flags); + PlotErrorBarsHEx(label_id, getter_p, getter_n, spec); } else { IndexerAdd,IndexerIdx> indexer_yp(indexer_y, indexer_p, 1, 1); IndexerAdd,IndexerIdx> indexer_yn(indexer_y, indexer_n, 1, -1); GetterXY,IndexerAdd,IndexerIdx>> getter_p(indexer_x, indexer_yp, count); GetterXY,IndexerAdd,IndexerIdx>> getter_n(indexer_x, indexer_yn, count); - PlotErrorBarsVEx(label_id, getter_p, getter_n, flags); + PlotErrorBarsVEx(label_id, getter_p, getter_n, spec); } } #define INSTANTIATE_MACRO(T) \ - template IMPLOT_API void PlotErrorBars(const char* label_id, const T* xs, const T* ys, const T* err, int count, ImPlotErrorBarsFlags flags, int offset, int stride); \ - template IMPLOT_API void PlotErrorBars(const char* label_id, const T* xs, const T* ys, const T* neg, const T* pos, int count, ImPlotErrorBarsFlags flags, int offset, int stride); + template IMPLOT_API void PlotErrorBars(const char* label_id, const T* xs, const T* ys, const T* err, int count, const ImPlotSpec& spec); \ + template IMPLOT_API void PlotErrorBars(const char* label_id, const T* xs, const T* ys, const T* neg, const T* pos, int count, const ImPlotSpec& spec); CALL_INSTANTIATE_FOR_NUMERIC_TYPES() #undef INSTANTIATE_MACRO @@ -2092,8 +2074,8 @@ CALL_INSTANTIATE_FOR_NUMERIC_TYPES() //----------------------------------------------------------------------------- template -void PlotStemsEx(const char* label_id, const _GetterM& getter_mark, const _GetterB& getter_base, ImPlotStemsFlags flags) { - if (BeginItemEx(label_id, Fitter2<_GetterM,_GetterB>(getter_mark,getter_base), flags, ImPlotCol_Line)) { +void PlotStemsEx(const char* label_id, const _GetterM& getter_mark, const _GetterB& getter_base, const ImPlotSpec& spec) { + if (BeginItemEx(label_id, Fitter2<_GetterM,_GetterB>(getter_mark,getter_base), spec, spec.LineColor, spec.Marker)) { if (getter_mark.Count <= 0 || getter_base.Count <= 0) { EndItem(); return; @@ -2101,52 +2083,52 @@ void PlotStemsEx(const char* label_id, const _GetterM& getter_mark, const _Gette const ImPlotNextItemData& s = GetItemData(); // render stems if (s.RenderLine) { - const ImU32 col_line = ImGui::GetColorU32(s.Colors[ImPlotCol_Line]); - RenderPrimitives2(getter_mark, getter_base, col_line, s.LineWeight); + const ImU32 col_line = ImGui::GetColorU32(s.Spec.LineColor); + RenderPrimitives2(getter_mark, getter_base, col_line, s.Spec.LineWeight); } // render markers - if (s.Marker != ImPlotMarker_None) { + if (s.RenderMarkers) { PopPlotClipRect(); - PushPlotClipRect(s.MarkerSize); - const ImU32 col_line = ImGui::GetColorU32(s.Colors[ImPlotCol_MarkerOutline]); - const ImU32 col_fill = ImGui::GetColorU32(s.Colors[ImPlotCol_MarkerFill]); - RenderMarkers<_GetterM>(getter_mark, s.Marker, s.MarkerSize, s.RenderMarkerFill, col_fill, s.RenderMarkerLine, col_line, s.MarkerWeight); + PushPlotClipRect(s.Spec.Size); + const ImU32 col_line = ImGui::GetColorU32(s.Spec.LineColor); + const ImU32 col_fill = ImGui::GetColorU32(s.Spec.FillColor); + RenderMarkers<_GetterM>(getter_mark, s.Spec.Marker, s.Spec.Size, s.RenderFill, col_fill, s.RenderLine, col_line, s.Spec.LineWeight); } EndItem(); } } template -void PlotStems(const char* label_id, const T* values, int count, double ref, double scale, double start, ImPlotStemsFlags flags, int offset, int stride) { - if (ImHasFlag(flags, ImPlotStemsFlags_Horizontal)) { - GetterXY,IndexerLin> get_mark(IndexerIdx(values,count,offset,stride),IndexerLin(scale,start),count); +void PlotStems(const char* label_id, const T* values, int count, double ref, double scale, double start, const ImPlotSpec& spec) { + if (ImHasFlag(spec.Flags, ImPlotStemsFlags_Horizontal)) { + GetterXY,IndexerLin> get_mark(IndexerIdx(values,count,spec.Offset,Stride(spec)),IndexerLin(scale,start),count); GetterXY get_base(IndexerConst(ref),IndexerLin(scale,start),count); - PlotStemsEx(label_id, get_mark, get_base, flags); + PlotStemsEx(label_id, get_mark, get_base, spec); } else { - GetterXY> get_mark(IndexerLin(scale,start),IndexerIdx(values,count,offset,stride),count); + GetterXY> get_mark(IndexerLin(scale,start),IndexerIdx(values,count,spec.Offset,Stride(spec)),count); GetterXY get_base(IndexerLin(scale,start),IndexerConst(ref),count); - PlotStemsEx(label_id, get_mark, get_base, flags); + PlotStemsEx(label_id, get_mark, get_base, spec); } } template -void PlotStems(const char* label_id, const T* xs, const T* ys, int count, double ref, ImPlotStemsFlags flags, int offset, int stride) { - if (ImHasFlag(flags, ImPlotStemsFlags_Horizontal)) { - GetterXY,IndexerIdx> get_mark(IndexerIdx(xs,count,offset,stride),IndexerIdx(ys,count,offset,stride),count); - GetterXY> get_base(IndexerConst(ref),IndexerIdx(ys,count,offset,stride),count); - PlotStemsEx(label_id, get_mark, get_base, flags); +void PlotStems(const char* label_id, const T* xs, const T* ys, int count, double ref, const ImPlotSpec& spec) { + if (ImHasFlag(spec.Flags, ImPlotStemsFlags_Horizontal)) { + GetterXY,IndexerIdx> get_mark(IndexerIdx(xs,count,spec.Offset,Stride(spec)),IndexerIdx(ys,count,spec.Offset,Stride(spec)),count); + GetterXY> get_base(IndexerConst(ref),IndexerIdx(ys,count,spec.Offset,Stride(spec)),count); + PlotStemsEx(label_id, get_mark, get_base, spec); } else { - GetterXY,IndexerIdx> get_mark(IndexerIdx(xs,count,offset,stride),IndexerIdx(ys,count,offset,stride),count); - GetterXY,IndexerConst> get_base(IndexerIdx(xs,count,offset,stride),IndexerConst(ref),count); - PlotStemsEx(label_id, get_mark, get_base, flags); + GetterXY,IndexerIdx> get_mark(IndexerIdx(xs,count,spec.Offset,Stride(spec)),IndexerIdx(ys,count,spec.Offset,Stride(spec)),count); + GetterXY,IndexerConst> get_base(IndexerIdx(xs,count,spec.Offset,Stride(spec)),IndexerConst(ref),count); + PlotStemsEx(label_id, get_mark, get_base, spec); } } #define INSTANTIATE_MACRO(T) \ - template IMPLOT_API void PlotStems(const char* label_id, const T* values, int count, double ref, double scale, double start, ImPlotStemsFlags flags, int offset, int stride); \ - template IMPLOT_API void PlotStems(const char* label_id, const T* xs, const T* ys, int count, double ref, ImPlotStemsFlags flags, int offset, int stride); + template IMPLOT_API void PlotStems(const char* label_id, const T* values, int count, double ref, double scale, double start, const ImPlotSpec& spec); \ + template IMPLOT_API void PlotStems(const char* label_id, const T* xs, const T* ys, int count, double ref, const ImPlotSpec& spec); CALL_INSTANTIATE_FOR_NUMERIC_TYPES() #undef INSTANTIATE_MACRO @@ -2156,40 +2138,40 @@ CALL_INSTANTIATE_FOR_NUMERIC_TYPES() //----------------------------------------------------------------------------- template -void PlotInfLines(const char* label_id, const T* values, int count, ImPlotInfLinesFlags flags, int offset, int stride) { +void PlotInfLines(const char* label_id, const T* values, int count, const ImPlotSpec& spec) { const ImPlotRect lims = GetPlotLimits(IMPLOT_AUTO,IMPLOT_AUTO); - if (ImHasFlag(flags, ImPlotInfLinesFlags_Horizontal)) { - GetterXY> getter_min(IndexerConst(lims.X.Min),IndexerIdx(values,count,offset,stride),count); - GetterXY> getter_max(IndexerConst(lims.X.Max),IndexerIdx(values,count,offset,stride),count); - if (BeginItemEx(label_id, FitterY>>(getter_min), flags, ImPlotCol_Line)) { + if (ImHasFlag(spec.Flags, ImPlotInfLinesFlags_Horizontal)) { + GetterXY> getter_min(IndexerConst(lims.X.Min),IndexerIdx(values,count,spec.Offset,Stride(spec)),count); + GetterXY> getter_max(IndexerConst(lims.X.Max),IndexerIdx(values,count,spec.Offset,Stride(spec)),count); + if (BeginItemEx(label_id, FitterY>>(getter_min), spec, spec.LineColor)) { if (count <= 0) { EndItem(); return; } const ImPlotNextItemData& s = GetItemData(); - const ImU32 col_line = ImGui::GetColorU32(s.Colors[ImPlotCol_Line]); + const ImU32 col_line = ImGui::GetColorU32(s.Spec.LineColor); if (s.RenderLine) - RenderPrimitives2(getter_min, getter_max, col_line, s.LineWeight); + RenderPrimitives2(getter_min, getter_max, col_line, s.Spec.LineWeight); EndItem(); } } else { - GetterXY,IndexerConst> get_min(IndexerIdx(values,count,offset,stride),IndexerConst(lims.Y.Min),count); - GetterXY,IndexerConst> get_max(IndexerIdx(values,count,offset,stride),IndexerConst(lims.Y.Max),count); - if (BeginItemEx(label_id, FitterX,IndexerConst>>(get_min), flags, ImPlotCol_Line)) { + GetterXY,IndexerConst> get_min(IndexerIdx(values,count,spec.Offset,Stride(spec)),IndexerConst(lims.Y.Min),count); + GetterXY,IndexerConst> get_max(IndexerIdx(values,count,spec.Offset,Stride(spec)),IndexerConst(lims.Y.Max),count); + if (BeginItemEx(label_id, FitterX,IndexerConst>>(get_min), spec, spec.LineColor)) { if (count <= 0) { EndItem(); return; } const ImPlotNextItemData& s = GetItemData(); - const ImU32 col_line = ImGui::GetColorU32(s.Colors[ImPlotCol_Line]); + const ImU32 col_line = ImGui::GetColorU32(s.Spec.LineColor); if (s.RenderLine) - RenderPrimitives2(get_min, get_max, col_line, s.LineWeight); + RenderPrimitives2(get_min, get_max, col_line, s.Spec.LineWeight); EndItem(); } } } -#define INSTANTIATE_MACRO(T) template IMPLOT_API void PlotInfLines(const char* label_id, const T* xs, int count, ImPlotInfLinesFlags flags, int offset, int stride); +#define INSTANTIATE_MACRO(T) template IMPLOT_API void PlotInfLines(const char* label_id, const T* xs, int count, const ImPlotSpec& spec); CALL_INSTANTIATE_FOR_NUMERIC_TYPES() #undef INSTANTIATE_MACRO @@ -2216,51 +2198,51 @@ IMPLOT_INLINE void RenderPieSlice(ImDrawList& draw_list, const ImPlotPoint& cent } template -double PieChartSum(const T* values, int count, bool ignore_hidden) { +double PieChartSum(IndexerIdx indexer, bool ignore_hidden) { double sum = 0; if (ignore_hidden) { ImPlotContext& gp = *GImPlot; ImPlotItemGroup& Items = *gp.CurrentItems; - for (int i = 0; i < count; ++i) { + for (int i = 0; i < indexer.Count; ++i) { if (i >= Items.GetItemCount()) break; ImPlotItem* item = Items.GetItemByIndex(i); IM_ASSERT(item != nullptr); if (item->Show) { - sum += (double)values[i]; + sum += (double)indexer[i]; } } } else { - for (int i = 0; i < count; ++i) { - sum += (double)values[i]; + for (int i = 0; i < indexer.Count; ++i) { + sum += (double)indexer[i]; } } return sum; } template -void PlotPieChartEx(const char* const label_ids[], const T* values, int count, ImPlotPoint center, double radius, double angle0, ImPlotPieChartFlags flags) { +void PlotPieChartEx(const char* const label_ids[], IndexerIdx indexer, ImPlotPoint center, double radius, double angle0, const ImPlotSpec& spec) { ImDrawList& draw_list = *GetPlotDrawList(); - const bool ignore_hidden = ImHasFlag(flags, ImPlotPieChartFlags_IgnoreHidden); - const double sum = PieChartSum(values, count, ignore_hidden); - const bool normalize = ImHasFlag(flags, ImPlotPieChartFlags_Normalize) || sum > 1.0; + const bool ignore_hidden = ImHasFlag(spec.Flags, ImPlotPieChartFlags_IgnoreHidden); + const double sum = PieChartSum(indexer, ignore_hidden); + const bool normalize = ImHasFlag(spec.Flags, ImPlotPieChartFlags_Normalize) || sum > 1.0; double a0 = angle0 * 2 * IM_PI / 360.0; double a1 = angle0 * 2 * IM_PI / 360.0; ImPlotPoint Pmin = ImPlotPoint(center.x - radius, center.y - radius); ImPlotPoint Pmax = ImPlotPoint(center.x + radius, center.y + radius); - for (int i = 0; i < count; ++i) { + for (int i = 0; i < indexer.Count; ++i) { ImPlotItem* item = GetItem(label_ids[i]); - const double percent = normalize ? (double)values[i] / sum : (double)values[i]; + const double percent = normalize ? (double)indexer[i] / sum : (double)indexer[i]; const bool skip = sum <= 0.0 || (ignore_hidden && item != nullptr && !item->Show); if (!skip) a1 = a0 + 2 * IM_PI * percent; - if (BeginItemEx(label_ids[i], FitterRect(Pmin, Pmax))) { + if (BeginItemEx(label_ids[i], FitterRect(Pmin, Pmax), spec)) { if (sum > 0.0) { ImU32 col = GetCurrentItem()->Color; if (percent < 0.5) { @@ -2284,25 +2266,27 @@ int PieChartFormatter(double value, char* buff, int size, void* data) { }; template -void PlotPieChart(const char* const label_ids[], const T* values, int count, double x, double y, double radius, const char* fmt, double angle0, ImPlotPieChartFlags flags) { - PlotPieChart(label_ids, values, count, x, y, radius, PieChartFormatter, (void*)fmt, angle0, flags); +void PlotPieChart(const char* const label_ids[], const T* values, int count, double x, double y, double radius, const char* fmt, double angle0, const ImPlotSpec& spec) { + PlotPieChart(label_ids, values, count, x, y, radius, PieChartFormatter, (void*)fmt, angle0, spec); } -#define INSTANTIATE_MACRO(T) template IMPLOT_API void PlotPieChart(const char* const label_ids[], const T* values, int count, double x, double y, double radius, const char* fmt, double angle0, ImPlotPieChartFlags flags); +#define INSTANTIATE_MACRO(T) template IMPLOT_API void PlotPieChart(const char* const label_ids[], const T* values, int count, double x, double y, double radius, const char* fmt, double angle0, const ImPlotSpec& spec); CALL_INSTANTIATE_FOR_NUMERIC_TYPES() #undef INSTANTIATE_MACRO template -void PlotPieChart(const char* const label_ids[], const T* values, int count, double x, double y, double radius, ImPlotFormatter fmt, void* fmt_data, double angle0, ImPlotPieChartFlags flags) { +void PlotPieChart(const char* const label_ids[], const T* values, int count, double x, double y, double radius, ImPlotFormatter fmt, void* fmt_data, double angle0, const ImPlotSpec& spec) { IM_ASSERT_USER_ERROR(GImPlot->CurrentPlot != nullptr, "PlotPieChart() needs to be called between BeginPlot() and EndPlot()!"); ImDrawList& draw_list = *GetPlotDrawList(); - const bool ignore_hidden = ImHasFlag(flags, ImPlotPieChartFlags_IgnoreHidden); - const double sum = PieChartSum(values, count, ignore_hidden); - const bool normalize = ImHasFlag(flags, ImPlotPieChartFlags_Normalize) || sum > 1.0; + IndexerIdx indexer(values,count,spec.Offset,Stride(spec)); + + const bool ignore_hidden = ImHasFlag(spec.Flags, ImPlotPieChartFlags_IgnoreHidden); + const double sum = PieChartSum(indexer, ignore_hidden); + const bool normalize = ImHasFlag(spec.Flags, ImPlotPieChartFlags_Normalize) || sum > 1.0; ImPlotPoint center(x, y); PushPlotClipRect(); - PlotPieChartEx(label_ids, values, count, center, radius, angle0, flags); + PlotPieChartEx(label_ids, indexer, center, radius, angle0, spec); if (fmt != nullptr) { double a0 = angle0 * 2 * IM_PI / 360.0; double a1 = angle0 * 2 * IM_PI / 360.0; @@ -2311,13 +2295,13 @@ void PlotPieChart(const char* const label_ids[], const T* values, int count, dou ImPlotItem* item = GetItem(label_ids[i]); IM_ASSERT(item != nullptr); - const double percent = normalize ? (double)values[i] / sum : (double)values[i]; + const double percent = normalize ? (double)indexer[i] / sum : (double)indexer[i]; const bool skip = ignore_hidden && item != nullptr && !item->Show; if (!skip) { a1 = a0 + 2 * IM_PI * percent; if (item->Show) { - fmt((double)values[i], buffer, 32, fmt_data); + fmt((double)indexer[i], buffer, 32, fmt_data); ImVec2 size = ImGui::CalcTextSize(buffer); double angle = a0 + (a1 - a0) * 0.5; ImVec2 pos = PlotToPixels(center.x + 0.5 * radius * cos(angle), center.y + 0.5 * radius * sin(angle), IMPLOT_AUTO, IMPLOT_AUTO); @@ -2330,7 +2314,7 @@ void PlotPieChart(const char* const label_ids[], const T* values, int count, dou } PopPlotClipRect(); } -#define INSTANTIATE_MACRO(T) template IMPLOT_API void PlotPieChart(const char* const label_ids[], const T* values, int count, double x, double y, double radius, ImPlotFormatter fmt, void* fmt_data, double angle0, ImPlotPieChartFlags flags); +#define INSTANTIATE_MACRO(T) template IMPLOT_API void PlotPieChart(const char* const label_ids[], const T* values, int count, double x, double y, double radius, ImPlotFormatter fmt, void* fmt_data, double angle0, const ImPlotSpec& spec); CALL_INSTANTIATE_FOR_NUMERIC_TYPES() #undef INSTANTIATE_MACRO @@ -2338,10 +2322,10 @@ CALL_INSTANTIATE_FOR_NUMERIC_TYPES() // [SECTION] PlotHeatmap //----------------------------------------------------------------------------- -template +template struct GetterHeatmapRowMaj { - GetterHeatmapRowMaj(const T* values, int rows, int cols, double scale_min, double scale_max, double width, double height, double xref, double yref, double ydir) : - Values(values), + GetterHeatmapRowMaj(_Indexer indexer, int rows, int cols, double scale_min, double scale_max, double width, double height, double xref, double yref, double ydir) : + Indexer(indexer), Count(rows*cols), Rows(rows), Cols(cols), @@ -2354,8 +2338,8 @@ struct GetterHeatmapRowMaj { YDir(ydir), HalfSize(Width*0.5, Height*0.5) { } - template IMPLOT_INLINE RectC operator()(I idx) const { - double val = (double)Values[idx]; + template IMPLOT_INLINE RectC operator[](I idx) const { + double val = (double)Indexer[idx]; const int r = idx / Cols; const int c = idx % Cols; const ImPlotPoint p(XRef + HalfSize.x + c*Width, YRef + YDir * (HalfSize.y + r*Height)); @@ -2367,16 +2351,17 @@ struct GetterHeatmapRowMaj { rect.Color = gp.ColormapData.LerpTable(gp.Style.Colormap, t); return rect; } - const T* const Values; + const _Indexer Indexer; const int Count, Rows, Cols; const double ScaleMin, ScaleMax, Width, Height, XRef, YRef, YDir; const ImPlotPoint HalfSize; + typedef RectC value_type; }; -template +template struct GetterHeatmapColMaj { - GetterHeatmapColMaj(const T* values, int rows, int cols, double scale_min, double scale_max, double width, double height, double xref, double yref, double ydir) : - Values(values), + GetterHeatmapColMaj(_Indexer indexer, int rows, int cols, double scale_min, double scale_max, double width, double height, double xref, double yref, double ydir) : + Indexer(indexer), Count(rows*cols), Rows(rows), Cols(cols), @@ -2389,8 +2374,8 @@ struct GetterHeatmapColMaj { YDir(ydir), HalfSize(Width*0.5, Height*0.5) { } - template IMPLOT_INLINE RectC operator()(I idx) const { - double val = (double)Values[idx]; + template IMPLOT_INLINE RectC operator[](I idx) const { + double val = (double)Indexer[idx]; const int r = idx % Rows; const int c = idx / Rows; const ImPlotPoint p(XRef + HalfSize.x + c*Width, YRef + YDir * (HalfSize.y + r*Height)); @@ -2402,21 +2387,20 @@ struct GetterHeatmapColMaj { rect.Color = gp.ColormapData.LerpTable(gp.Style.Colormap, t); return rect; } - const T* const Values; + // const T* const Values; + const _Indexer Indexer; const int Count, Rows, Cols; const double ScaleMin, ScaleMax, Width, Height, XRef, YRef, YDir; const ImPlotPoint HalfSize; + typedef RectC value_type; }; template -void RenderHeatmap(ImDrawList& draw_list, const T* values, int rows, int cols, double scale_min, double scale_max, const char* fmt, const ImPlotPoint& bounds_min, const ImPlotPoint& bounds_max, bool reverse_y, bool col_maj) { +void RenderHeatmap(ImDrawList& draw_list, IndexerIdx indexer, int rows, int cols, double scale_min, double scale_max, const char* fmt, const ImPlotPoint& bounds_min, const ImPlotPoint& bounds_max, bool reverse_y, bool col_maj) { ImPlotContext& gp = *GImPlot; Transformer2 transformer; if (scale_min == 0 && scale_max == 0) { - T temp_min, temp_max; - ImMinMaxArray(values,rows*cols,&temp_min,&temp_max); - scale_min = (double)temp_min; - scale_max = (double)temp_max; + ImMinMaxArray(indexer,rows*cols,&scale_min,&scale_max); } if (scale_min == scale_max) { ImVec2 a = transformer(bounds_min); @@ -2428,11 +2412,11 @@ void RenderHeatmap(ImDrawList& draw_list, const T* values, int rows, int cols, d const double yref = reverse_y ? bounds_max.y : bounds_min.y; const double ydir = reverse_y ? -1 : 1; if (col_maj) { - GetterHeatmapColMaj getter(values, rows, cols, scale_min, scale_max, (bounds_max.x - bounds_min.x) / cols, (bounds_max.y - bounds_min.y) / rows, bounds_min.x, yref, ydir); + GetterHeatmapColMaj> getter(indexer, rows, cols, scale_min, scale_max, (bounds_max.x - bounds_min.x) / cols, (bounds_max.y - bounds_min.y) / rows, bounds_min.x, yref, ydir); RenderPrimitives1(getter); } else { - GetterHeatmapRowMaj getter(values, rows, cols, scale_min, scale_max, (bounds_max.x - bounds_min.x) / cols, (bounds_max.y - bounds_min.y) / rows, bounds_min.x, yref, ydir); + GetterHeatmapRowMaj> getter(indexer, rows, cols, scale_min, scale_max, (bounds_max.x - bounds_min.x) / cols, (bounds_max.y - bounds_min.y) / rows, bounds_min.x, yref, ydir); RenderPrimitives1(getter); } // labels @@ -2449,9 +2433,9 @@ void RenderHeatmap(ImDrawList& draw_list, const T* values, int rows, int cols, d p.y = yref + ydir * (0.5*h + r*h); ImVec2 px = transformer(p); char buff[32]; - ImFormatString(buff, 32, fmt, values[i]); + ImFormatString(buff, 32, fmt, indexer[i]); ImVec2 size = ImGui::CalcTextSize(buff); - double t = ImClamp(ImRemap01((double)values[i], scale_min, scale_max),0.0,1.0); + double t = ImClamp(ImRemap01((double)indexer[i], scale_min, scale_max),0.0,1.0); ImVec4 color = SampleColormap((float)t); ImU32 col = CalcTextColor(color); draw_list.AddText(px - size * 0.5f, col, buff); @@ -2467,9 +2451,9 @@ void RenderHeatmap(ImDrawList& draw_list, const T* values, int rows, int cols, d p.y = yref + ydir * (0.5*h + r*h); ImVec2 px = transformer(p); char buff[32]; - ImFormatString(buff, 32, fmt, values[i]); + ImFormatString(buff, 32, fmt, indexer[i]); ImVec2 size = ImGui::CalcTextSize(buff); - double t = ImClamp(ImRemap01((double)values[i], scale_min, scale_max),0.0,1.0); + double t = ImClamp(ImRemap01((double)indexer[i], scale_min, scale_max),0.0,1.0); ImVec4 color = SampleColormap((float)t); ImU32 col = CalcTextColor(color); draw_list.AddText(px - size * 0.5f, col, buff); @@ -2481,19 +2465,20 @@ void RenderHeatmap(ImDrawList& draw_list, const T* values, int rows, int cols, d } template -void PlotHeatmap(const char* label_id, const T* values, int rows, int cols, double scale_min, double scale_max, const char* fmt, const ImPlotPoint& bounds_min, const ImPlotPoint& bounds_max, ImPlotHeatmapFlags flags) { - if (BeginItemEx(label_id, FitterRect(bounds_min, bounds_max))) { +void PlotHeatmap(const char* label_id, const T* values, int rows, int cols, double scale_min, double scale_max, const char* fmt, const ImPlotPoint& bounds_min, const ImPlotPoint& bounds_max, const ImPlotSpec& spec) { + if (BeginItemEx(label_id, FitterRect(bounds_min, bounds_max), spec)) { if (rows <= 0 || cols <= 0) { EndItem(); return; } ImDrawList& draw_list = *GetPlotDrawList(); - const bool col_maj = ImHasFlag(flags, ImPlotHeatmapFlags_ColMajor); - RenderHeatmap(draw_list, values, rows, cols, scale_min, scale_max, fmt, bounds_min, bounds_max, true, col_maj); + const bool col_maj = ImHasFlag(spec.Flags, ImPlotHeatmapFlags_ColMajor); + IndexerIdx indexer(values,rows*cols,spec.Offset,Stride(spec)); + RenderHeatmap(draw_list, indexer, rows, cols, scale_min, scale_max, fmt, bounds_min, bounds_max, true, col_maj); EndItem(); } } -#define INSTANTIATE_MACRO(T) template IMPLOT_API void PlotHeatmap(const char* label_id, const T* values, int rows, int cols, double scale_min, double scale_max, const char* fmt, const ImPlotPoint& bounds_min, const ImPlotPoint& bounds_max, ImPlotHeatmapFlags flags); +#define INSTANTIATE_MACRO(T) template IMPLOT_API void PlotHeatmap(const char* label_id, const T* values, int rows, int cols, double scale_min, double scale_max, const char* fmt, const ImPlotPoint& bounds_min, const ImPlotPoint& bounds_max, const ImPlotSpec& spec); CALL_INSTANTIATE_FOR_NUMERIC_TYPES() #undef INSTANTIATE_MACRO @@ -2502,25 +2487,24 @@ CALL_INSTANTIATE_FOR_NUMERIC_TYPES() //----------------------------------------------------------------------------- template -double PlotHistogram(const char* label_id, const T* values, int count, int bins, double bar_scale, ImPlotRange range, ImPlotHistogramFlags flags) { +double PlotHistogram(const char* label_id, const T* values, int count, int bins, double bar_scale, ImPlotRange range, const ImPlotSpec& spec) { + + const bool cumulative = ImHasFlag(spec.Flags, ImPlotHistogramFlags_Cumulative); + const bool density = ImHasFlag(spec.Flags, ImPlotHistogramFlags_Density); + const bool outliers = !ImHasFlag(spec.Flags, ImPlotHistogramFlags_NoOutliers); - const bool cumulative = ImHasFlag(flags, ImPlotHistogramFlags_Cumulative); - const bool density = ImHasFlag(flags, ImPlotHistogramFlags_Density); - const bool outliers = !ImHasFlag(flags, ImPlotHistogramFlags_NoOutliers); + IndexerIdx indexer(values,count,spec.Offset,Stride(spec)); if (count <= 0 || bins == 0) return 0; if (range.Min == 0 && range.Max == 0) { - T Min, Max; - ImMinMaxArray(values, count, &Min, &Max); - range.Min = (double)Min; - range.Max = (double)Max; + ImMinMaxArray(indexer, count, &range.Min, &range.Max); } double width; if (bins < 0) - CalculateBins(values, count, bins, range, bins, width); + CalculateBins(indexer, count, bins, range, bins, width); else width = range.Size() / bins; @@ -2538,7 +2522,7 @@ double PlotHistogram(const char* label_id, const T* values, int count, int bins, int counted = 0; double max_count = 0; for (int i = 0; i < count; ++i) { - double val = (double)values[i]; + double val = indexer[i]; if (range.Contains(val)) { const int b = ImClamp((int)((val - range.Min) / width), 0, bins - 1); bin_counts[b] += 1.0; @@ -2573,13 +2557,18 @@ double PlotHistogram(const char* label_id, const T* values, int count, int bins, bin_counts[b] *= scale; max_count *= scale; } - if (ImHasFlag(flags, ImPlotHistogramFlags_Horizontal)) - PlotBars(label_id, &bin_counts.Data[0], &bin_centers.Data[0], bins, bar_scale*width, ImPlotBarsFlags_Horizontal); - else - PlotBars(label_id, &bin_centers.Data[0], &bin_counts.Data[0], bins, bar_scale*width); + ImPlotSpec spec_bars = spec; + if (ImHasFlag(spec.Flags, ImPlotHistogramFlags_Horizontal)) { + spec_bars.Flags = ImPlotBarsFlags_Horizontal; + PlotBars(label_id, &bin_counts.Data[0], &bin_centers.Data[0], bins, bar_scale*width, spec_bars); + } + else { + spec_bars.Flags = 0; + PlotBars(label_id, &bin_centers.Data[0], &bin_counts.Data[0], bins, bar_scale*width, spec_bars); + } return max_count; } -#define INSTANTIATE_MACRO(T) template IMPLOT_API double PlotHistogram(const char* label_id, const T* values, int count, int bins, double bar_scale, ImPlotRange range, ImPlotHistogramFlags flags); +#define INSTANTIATE_MACRO(T) template IMPLOT_API double PlotHistogram(const char* label_id, const T* values, int count, int bins, double bar_scale, ImPlotRange range, const ImPlotSpec& spec); CALL_INSTANTIATE_FOR_NUMERIC_TYPES() #undef INSTANTIATE_MACRO @@ -2588,36 +2577,33 @@ CALL_INSTANTIATE_FOR_NUMERIC_TYPES() //----------------------------------------------------------------------------- template -double PlotHistogram2D(const char* label_id, const T* xs, const T* ys, int count, int x_bins, int y_bins, ImPlotRect range, ImPlotHistogramFlags flags) { +double PlotHistogram2D(const char* label_id, const T* xs, const T* ys, int count, int x_bins, int y_bins, ImPlotRect range, const ImPlotSpec& spec) { // const bool cumulative = ImHasFlag(flags, ImPlotHistogramFlags_Cumulative); NOT SUPPORTED - const bool density = ImHasFlag(flags, ImPlotHistogramFlags_Density); - const bool outliers = !ImHasFlag(flags, ImPlotHistogramFlags_NoOutliers); - const bool col_maj = ImHasFlag(flags, ImPlotHistogramFlags_ColMajor); + const bool density = ImHasFlag(spec.Flags, ImPlotHistogramFlags_Density); + const bool outliers = !ImHasFlag(spec.Flags, ImPlotHistogramFlags_NoOutliers); + const bool col_maj = ImHasFlag(spec.Flags, ImPlotHistogramFlags_ColMajor); + + IndexerIdx indexer_x(xs,count,spec.Offset,Stride(spec)); + IndexerIdx indexer_y(ys,count,spec.Offset,Stride(spec)); if (count <= 0 || x_bins == 0 || y_bins == 0) return 0; if (range.X.Min == 0 && range.X.Max == 0) { - T Min, Max; - ImMinMaxArray(xs, count, &Min, &Max); - range.X.Min = (double)Min; - range.X.Max = (double)Max; + ImMinMaxArray(indexer_x, count, &range.X.Min, &range.X.Min); } if (range.Y.Min == 0 && range.Y.Max == 0) { - T Min, Max; - ImMinMaxArray(ys, count, &Min, &Max); - range.Y.Min = (double)Min; - range.Y.Max = (double)Max; + ImMinMaxArray(indexer_y, count, &range.Y.Min, &range.Y.Max); } double width, height; if (x_bins < 0) - CalculateBins(xs, count, x_bins, range.X, x_bins, width); + CalculateBins(indexer_x, count, x_bins, range.X, x_bins, width); else width = range.X.Size() / x_bins; if (y_bins < 0) - CalculateBins(ys, count, y_bins, range.Y, y_bins, height); + CalculateBins(indexer_y, count, y_bins, range.Y, y_bins, height); else height = range.Y.Size() / y_bins; @@ -2633,9 +2619,9 @@ double PlotHistogram2D(const char* label_id, const T* xs, const T* ys, int count int counted = 0; double max_count = 0; for (int i = 0; i < count; ++i) { - if (range.Contains((double)xs[i], (double)ys[i])) { - const int xb = ImClamp( (int)((double)(xs[i] - range.X.Min) / width) , 0, x_bins - 1); - const int yb = ImClamp( (int)((double)(ys[i] - range.Y.Min) / height) , 0, y_bins - 1); + if (range.Contains(indexer_x[i], indexer_y[i])) { + const int xb = ImClamp( (int)((indexer_x[i] - range.X.Min) / width) , 0, x_bins - 1); + const int yb = ImClamp( (int)((indexer_y[i] - range.Y.Min) / height) , 0, y_bins - 1); const int b = yb * x_bins + xb; bin_counts[b] += 1.0; if (bin_counts[b] > max_count) @@ -2650,18 +2636,19 @@ double PlotHistogram2D(const char* label_id, const T* xs, const T* ys, int count max_count *= scale; } - if (BeginItemEx(label_id, FitterRect(range))) { + if (BeginItemEx(label_id, FitterRect(range), spec)) { if (y_bins <= 0 || x_bins <= 0) { EndItem(); return max_count; } ImDrawList& draw_list = *GetPlotDrawList(); - RenderHeatmap(draw_list, &bin_counts.Data[0], y_bins, x_bins, 0, max_count, nullptr, range.Min(), range.Max(), false, col_maj); + IndexerIdx indexer_bin(bin_counts.begin(), y_bins*x_bins, 0, sizeof(double)); + RenderHeatmap(draw_list, indexer_bin, y_bins, x_bins, 0, max_count, nullptr, range.Min(), range.Max(), false, col_maj); EndItem(); } return max_count; } -#define INSTANTIATE_MACRO(T) template IMPLOT_API double PlotHistogram2D(const char* label_id, const T* xs, const T* ys, int count, int x_bins, int y_bins, ImPlotRect range, ImPlotHistogramFlags flags); +#define INSTANTIATE_MACRO(T) template IMPLOT_API double PlotHistogram2D(const char* label_id, const T* xs, const T* ys, int count, int x_bins, int y_bins, ImPlotRect range, const ImPlotSpec& spec); CALL_INSTANTIATE_FOR_NUMERIC_TYPES() #undef INSTANTIATE_MACRO @@ -2670,10 +2657,11 @@ CALL_INSTANTIATE_FOR_NUMERIC_TYPES() //----------------------------------------------------------------------------- // TODO: Make this behave like all the other plot types (.e. not fixed in y axis) +// TODO: Currently broken if x or y axis is inverted! (what should happen in this case, anyway?) template -void PlotDigitalEx(const char* label_id, Getter getter, ImPlotDigitalFlags flags) { - if (BeginItem(label_id, flags, ImPlotCol_Fill)) { +void PlotDigitalEx(const char* label_id, Getter getter, const ImPlotSpec& spec) { + if (BeginItem(label_id, spec, spec.FillColor)) { ImPlotContext& gp = *GImPlot; ImDrawList& draw_list = *GetPlotDrawList(); const ImPlotNextItemData& s = GetItemData(); @@ -2683,34 +2671,36 @@ void PlotDigitalEx(const char* label_id, Getter getter, ImPlotDigitalFlags flags ImPlotAxis& y_axis = plot.Axes[plot.CurrentY]; int pixYMax = 0; - ImPlotPoint itemData1 = getter(0); + ImPlotPoint itemData1 = getter[0]; for (int i = 0; i < getter.Count; ++i) { - ImPlotPoint itemData2 = getter(i); + ImPlotPoint itemData2 = getter[i]; if (ImNanOrInf(itemData1.y)) { itemData1 = itemData2; continue; } - if (ImNanOrInf(itemData2.y)) itemData2.y = ImConstrainNan(ImConstrainInf(itemData2.y)); - int pixY_0 = (int)(s.LineWeight); + if (ImNanOrInf(itemData2.y)) { + itemData2.y = ImConstrainNan(ImConstrainInf(itemData2.y)); + } + int pixY_0 = (int)(s.Spec.LineWeight); itemData1.y = ImMax(0.0, itemData1.y); - float pixY_1_float = s.DigitalBitHeight * (float)itemData1.y; + float pixY_1_float = s.Spec.Size * (float)itemData1.y; int pixY_1 = (int)(pixY_1_float); //allow only positive values - int pixY_chPosOffset = (int)(ImMax(s.DigitalBitHeight, pixY_1_float) + s.DigitalBitGap); + int pixY_chPosOffset = (int)(ImMax(s.Spec.Size, pixY_1_float) + gp.Style.DigitalSpacing); pixYMax = ImMax(pixYMax, pixY_chPosOffset); ImVec2 pMin = PlotToPixels(itemData1,IMPLOT_AUTO,IMPLOT_AUTO); ImVec2 pMax = PlotToPixels(itemData2,IMPLOT_AUTO,IMPLOT_AUTO); - int pixY_Offset = 0; //20 pixel from bottom due to mouse cursor label - pMin.y = (y_axis.PixelMin) + ((-gp.DigitalPlotOffset) - pixY_Offset); - pMax.y = (y_axis.PixelMin) + ((-gp.DigitalPlotOffset) - pixY_0 - pixY_1 - pixY_Offset); + int pixY_Offset = (int)gp.Style.DigitalPadding; + pMin.y = y_axis.PixelMin + (-gp.DigitalPlotOffset - pixY_Offset); + pMax.y = y_axis.PixelMin + (-gp.DigitalPlotOffset - pixY_0 - pixY_1 - pixY_Offset); //plot only one rectangle for same digital state while (((i+2) < getter.Count) && (itemData1.y == itemData2.y)) { const int in = (i + 1); - itemData2 = getter(in); + itemData2 = getter[in]; if (ImNanOrInf(itemData2.y)) break; pMax.x = PlotToPixels(itemData2,IMPLOT_AUTO,IMPLOT_AUTO).x; i++; } - //do not extend plot outside plot range + // do not extend plot outside plot range if (pMin.x < x_axis.PixelMin) pMin.x = x_axis.PixelMin; if (pMax.x < x_axis.PixelMin) pMax.x = x_axis.PixelMin; if (pMin.x > x_axis.PixelMax) pMin.x = x_axis.PixelMax - 1; //fix issue related to https://github.com/ocornut/imgui/issues/3976 @@ -2719,7 +2709,7 @@ void PlotDigitalEx(const char* label_id, Getter getter, ImPlotDigitalFlags flags if ((pMax.x > pMin.x) && (gp.CurrentPlot->PlotRect.Contains(pMin) || gp.CurrentPlot->PlotRect.Contains(pMax))) { // ImVec4 colAlpha = item->Color; // colAlpha.w = item->Highlight ? 1.0f : 0.9f; - draw_list.AddRectFilled(pMin, pMax, ImGui::GetColorU32(s.Colors[ImPlotCol_Fill])); + draw_list.AddRectFilled(pMin, pMax, ImGui::GetColorU32(s.Spec.FillColor)); } itemData1 = itemData2; } @@ -2732,26 +2722,26 @@ void PlotDigitalEx(const char* label_id, Getter getter, ImPlotDigitalFlags flags template -void PlotDigital(const char* label_id, const T* xs, const T* ys, int count, ImPlotDigitalFlags flags, int offset, int stride) { - GetterXY,IndexerIdx> getter(IndexerIdx(xs,count,offset,stride),IndexerIdx(ys,count,offset,stride),count); - return PlotDigitalEx(label_id, getter, flags); +void PlotDigital(const char* label_id, const T* xs, const T* ys, int count, const ImPlotSpec& spec) { + GetterXY,IndexerIdx> getter(IndexerIdx(xs,count,spec.Offset,Stride(spec)),IndexerIdx(ys,count,spec.Offset,Stride(spec)),count); + return PlotDigitalEx(label_id, getter, spec); } -#define INSTANTIATE_MACRO(T) template IMPLOT_API void PlotDigital(const char* label_id, const T* xs, const T* ys, int count, ImPlotDigitalFlags flags, int offset, int stride); +#define INSTANTIATE_MACRO(T) template IMPLOT_API void PlotDigital(const char* label_id, const T* xs, const T* ys, int count, const ImPlotSpec& spec); CALL_INSTANTIATE_FOR_NUMERIC_TYPES() #undef INSTANTIATE_MACRO // custom -void PlotDigitalG(const char* label_id, ImPlotGetter getter_func, void* data, int count, ImPlotDigitalFlags flags) { +void PlotDigitalG(const char* label_id, ImPlotGetter getter_func, void* data, int count, const ImPlotSpec& spec) { GetterFuncPtr getter(getter_func,data,count); - return PlotDigitalEx(label_id, getter, flags); + return PlotDigitalEx(label_id, getter, spec); } //----------------------------------------------------------------------------- // [SECTION] PlotImage //----------------------------------------------------------------------------- -void PlotImage(const char* label_id, ImTextureID user_texture_id, const ImPlotPoint& bmin, const ImPlotPoint& bmax, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& tint_col, ImPlotImageFlags) { - if (BeginItemEx(label_id, FitterRect(bmin,bmax))) { +void PlotImage(const char* label_id, ImTextureID user_texture_id, const ImPlotPoint& bmin, const ImPlotPoint& bmax, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& tint_col, const ImPlotSpec& spec) { + if (BeginItemEx(label_id, FitterRect(bmin,bmax), spec)) { ImU32 tint_col32 = ImGui::ColorConvertFloat4ToU32(tint_col); GetCurrentItem()->Color = tint_col32; ImDrawList& draw_list = *GetPlotDrawList(); @@ -2768,17 +2758,17 @@ void PlotImage(const char* label_id, ImTextureID user_texture_id, const ImPlotPo // [SECTION] PlotText //----------------------------------------------------------------------------- -void PlotText(const char* text, double x, double y, const ImVec2& pixel_offset, ImPlotTextFlags flags) { +void PlotText(const char* text, double x, double y, const ImVec2& pixel_offset, const ImPlotSpec& spec) { IM_ASSERT_USER_ERROR(GImPlot->CurrentPlot != nullptr, "PlotText() needs to be called between BeginPlot() and EndPlot()!"); SetupLock(); ImDrawList & draw_list = *GetPlotDrawList(); PushPlotClipRect(); ImU32 colTxt = GetStyleColorU32(ImPlotCol_InlayText); - if (ImHasFlag(flags,ImPlotTextFlags_Vertical)) { + if (ImHasFlag(spec.Flags,ImPlotTextFlags_Vertical)) { ImVec2 siz = CalcTextSizeVertical(text) * 0.5f; ImVec2 ctr = siz * 0.5f; ImVec2 pos = PlotToPixels(ImPlotPoint(x,y),IMPLOT_AUTO,IMPLOT_AUTO) + ImVec2(-ctr.x, ctr.y) + pixel_offset; - if (FitThisFrame() && !ImHasFlag(flags, ImPlotItemFlags_NoFit)) { + if (FitThisFrame() && !ImHasFlag(spec.Flags, ImPlotItemFlags_NoFit)) { FitPoint(PixelsToPlot(pos)); FitPoint(PixelsToPlot(pos.x + siz.x, pos.y - siz.y)); } @@ -2787,7 +2777,7 @@ void PlotText(const char* text, double x, double y, const ImVec2& pixel_offset, else { ImVec2 siz = ImGui::CalcTextSize(text); ImVec2 pos = PlotToPixels(ImPlotPoint(x,y),IMPLOT_AUTO,IMPLOT_AUTO) - siz * 0.5f + pixel_offset; - if (FitThisFrame() && !ImHasFlag(flags, ImPlotItemFlags_NoFit)) { + if (FitThisFrame() && !ImHasFlag(spec.Flags, ImPlotItemFlags_NoFit)) { FitPoint(PixelsToPlot(pos)); FitPoint(PixelsToPlot(pos+siz)); } @@ -2800,8 +2790,8 @@ void PlotText(const char* text, double x, double y, const ImVec2& pixel_offset, // [SECTION] PlotDummy //----------------------------------------------------------------------------- -void PlotDummy(const char* label_id, ImPlotDummyFlags flags) { - if (BeginItem(label_id, flags, ImPlotCol_Line)) +void PlotDummy(const char* label_id, const ImPlotSpec& spec) { + if (BeginItem(label_id, spec)) EndItem(); }