From c0fe2710018225ba81d431f6dd0031e8ad18819d Mon Sep 17 00:00:00 2001 From: epezent Date: Sat, 30 Sep 2023 03:18:30 -0500 Subject: [PATCH 01/21] Add ImPlotSpec and remove existing plot item styling mechanisms (SetNext, PushStyle, etc.) --- README.md | 8 +- implot.cpp | 91 ++----- implot.h | 215 +++++++++-------- implot_demo.cpp | 301 +++++++++++++---------- implot_internal.h | 30 +-- implot_items.cpp | 593 ++++++++++++++++++++++------------------------ 6 files changed, 602 insertions(+), 636 deletions(-) diff --git a/README.md b/README.md index 9443bd8a..b40518cd 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 5550d031..db5d5504 100644 --- a/implot.cpp +++ b/implot.cpp @@ -32,6 +32,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/09/29 (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. + - 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/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. @@ -170,18 +178,7 @@ ImPlotInputMap::ImPlotInputMap() { ImPlot::MapInputDefault(this); } -ImPlotStyle::ImPlotStyle() { - - LineWeight = 1; - Marker = ImPlotMarker_None; - MarkerSize = 4; - MarkerWeight = 1; - FillAlpha = 1; - ErrorBarSize = 5; - ErrorBarWeight = 1.5f; - DigitalBitHeight = 8; - DigitalBitGap = 4; - +ImPlotStyle::ImPlotStyle() { PlotBorderSize = 1; MinorAlpha = 0.25f; MajorTickLen = ImVec2(10,10); @@ -200,7 +197,9 @@ ImPlotStyle::ImPlotStyle() { FitPadding = ImVec2(0,0); PlotDefaultSize = ImVec2(400,300); PlotMinSize = ImVec2(200,150); - + DigitalBitHeight = 8; + DigitalBitGap = 4; + ImPlot::StyleColorsAuto(this); Colormap = ImPlotColormap_Deep; @@ -218,11 +217,6 @@ namespace ImPlot { const char* GetStyleColorName(ImPlotCol col) { static const char* col_names[ImPlotCol_COUNT] = { - "Line", - "Fill", - "MarkerOutline", - "MarkerFill", - "ErrorBar", "FrameBg", "PlotBg", "PlotBorder", @@ -263,11 +257,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); @@ -297,16 +286,8 @@ struct ImPlotStyleVarInfo { static const ImPlotStyleVarInfo GPlotStyleVarInfo[] = { - { ImGuiDataType_Float, 1, (ImU32)offsetof(ImPlotStyle, LineWeight) }, // ImPlotStyleVar_LineWeight - { ImGuiDataType_S32, 1, (ImU32)offsetof(ImPlotStyle, Marker) }, // ImPlotStyleVar_Marker - { ImGuiDataType_Float, 1, (ImU32)offsetof(ImPlotStyle, MarkerSize) }, // ImPlotStyleVar_MarkerSize - { ImGuiDataType_Float, 1, (ImU32)offsetof(ImPlotStyle, MarkerWeight) }, // ImPlotStyleVar_MarkerWeight - { ImGuiDataType_Float, 1, (ImU32)offsetof(ImPlotStyle, FillAlpha) }, // ImPlotStyleVar_FillAlpha - { ImGuiDataType_Float, 1, (ImU32)offsetof(ImPlotStyle, ErrorBarSize) }, // ImPlotStyleVar_ErrorBarSize - { ImGuiDataType_Float, 1, (ImU32)offsetof(ImPlotStyle, ErrorBarWeight) }, // ImPlotStyleVar_ErrorBarWeight - { ImGuiDataType_Float, 1, (ImU32)offsetof(ImPlotStyle, DigitalBitHeight) }, // ImPlotStyleVar_DigitalBitHeight - { ImGuiDataType_Float, 1, (ImU32)offsetof(ImPlotStyle, DigitalBitGap) }, // ImPlotStyleVar_DigitalBitGap - + { ImGuiDataType_Float, 2, (ImU32)offsetof(ImPlotStyle, PlotDefaultSize) }, // ImPlotStyleVar_PlotDefaultSize + { ImGuiDataType_Float, 2, (ImU32)offsetof(ImPlotStyle, PlotMinSize) } // ImPlotStyleVar_PlotMinSize { ImGuiDataType_Float, 1, (ImU32)offsetof(ImPlotStyle, PlotBorderSize) }, // ImPlotStyleVar_PlotBorderSize { ImGuiDataType_Float, 1, (ImU32)offsetof(ImPlotStyle, MinorAlpha) }, // ImPlotStyleVar_MinorAlpha { ImGuiDataType_Float, 2, (ImU32)offsetof(ImPlotStyle, MajorTickLen) }, // ImPlotStyleVar_MajorTickLen @@ -320,12 +301,11 @@ static const ImPlotStyleVarInfo GPlotStyleVarInfo[] = { ImGuiDataType_Float, 2, (ImU32)offsetof(ImPlotStyle, LegendPadding) }, // ImPlotStyleVar_LegendPadding { ImGuiDataType_Float, 2, (ImU32)offsetof(ImPlotStyle, LegendInnerPadding) }, // ImPlotStyleVar_LegendInnerPadding { ImGuiDataType_Float, 2, (ImU32)offsetof(ImPlotStyle, LegendSpacing) }, // ImPlotStyleVar_LegendSpacing - { ImGuiDataType_Float, 2, (ImU32)offsetof(ImPlotStyle, MousePosPadding) }, // ImPlotStyleVar_MousePosPadding { ImGuiDataType_Float, 2, (ImU32)offsetof(ImPlotStyle, AnnotationPadding) }, // ImPlotStyleVar_AnnotationPadding { ImGuiDataType_Float, 2, (ImU32)offsetof(ImPlotStyle, FitPadding) }, // ImPlotStyleVar_FitPadding - { ImGuiDataType_Float, 2, (ImU32)offsetof(ImPlotStyle, PlotDefaultSize) }, // ImPlotStyleVar_PlotDefaultSize - { ImGuiDataType_Float, 2, (ImU32)offsetof(ImPlotStyle, PlotMinSize) } // ImPlotStyleVar_PlotMinSize + { ImGuiDataType_Float, 2, (ImU32)offsetof(ImPlotStyle, DigitalPadding) }, // ImPlotStyleVar_DigitalPadding + { ImGuiDataType_Float, 1, (ImU32)offsetof(ImPlotStyle, DigitalSpacing) }, // ImPlotStyleVar_DigitalSpacing }; static const ImPlotStyleVarInfo* GetPlotStyleVarInfo(ImPlotStyleVar idx) { @@ -4957,15 +4937,6 @@ 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::SliderFloat("PlotBorderSize", &style.PlotBorderSize, 0.0f, 2.0f, "%.0f"); ImGui::SliderFloat("MinorAlpha", &style.MinorAlpha, 0.0f, 1.0f, "%.2f"); @@ -4986,7 +4957,9 @@ 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::Text("Miscellaneous"); + ImGui::SliderFloat("DigitalBitHeight", &style.DigitalBitHeight, 0.0f, 20.0f, "%.1f"); + ImGui::SliderFloat("DigitalBitGap", &style.DigitalBitGap, 0.0f, 20.0f, "%.1f"); ImGui::EndTabItem(); } if (ImGui::BeginTabItem("Colors")) { @@ -5069,9 +5042,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")) { @@ -5763,11 +5734,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; @@ -5792,12 +5758,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); @@ -5822,11 +5783,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); @@ -5851,11 +5807,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 67b90c6f..72712864 100644 --- a/implot.h +++ b/implot.h @@ -81,6 +81,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_ @@ -116,6 +117,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 @@ -130,6 +132,19 @@ enum ImAxis_ { ImAxis_COUNT }; +// Plotting properties +enum ImProp_ { + ImProp_LineColor, + ImProp_LineWeight, + ImProp_FillColor, + ImProp_FillAlpha, + ImProp_Marker, + ImProp_Size, + ImProp_Offset, + ImProp_Stride, + ImProp_Flags +}; + // Options for plots (see BeginPlot). enum ImPlotFlags_ { ImPlotFlags_None = 0, // default @@ -344,13 +359,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) @@ -372,17 +380,6 @@ 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_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 @@ -401,6 +398,8 @@ enum ImPlotStyleVar_ { 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_DigitalBitHeight, // float, digital channels bit height (at 1) in pixels + ImPlotStyleVar_DigitalBitGap, // float, digital channels bit padding gap in pixels ImPlotStyleVar_COUNT }; @@ -469,6 +468,60 @@ enum ImPlotBin_ { ImPlotBin_Scott = -4, // w = 3.49 * sigma / cbrt(n) }; +// Plot item styling specification data +// TODO: merge with ImPlotNextItemData +// issues: +// - need to verify that stride offset work on functions previously not accepting them +// - next plot item data needed? + +struct ImPlotSpec { + ImVec4 LineColor = IMPLOT_AUTO_COL; // line color (applies to line, bar edges, marker edges) + float LineWeight = 1.0f; // line weight in pixels (applies to lines, bar edges, marker edges) + ImVec4 FillColor = IMPLOT_AUTO_COL; // fill color (applies to bar faces and shaded regions) + float FillAlpha = 1.0f; // alpha multiplier (applies to FillColor) + ImPlotMarker Marker = ImPlotMarker_None; // marker type + float Size = 4; // size of markers (radius) and error bar whiskers (widget/height) in pixels + int Offset = 0; // data offset + int Stride = IMPLOT_AUTO; // data stride; defaults to sizeof(T) where T is the type passed to PlotX + ImPlotItemFlags Flags = 0; // item flags + + ImPlotSpec() { } + + template + ImPlotSpec(Args... args) { + static_assert((sizeof ...(Args)) % 2 == 0, "Incorrect number of arguments!"); + SetProp(args...); + } + + template + void SetProp(ImProp prop, Arg arg, Args... args) { + SetProp(prop, arg); + SetProp(args...); + } + + 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; + } + } + + void SetProp(ImProp prop, const ImVec4& v) { + switch (prop) { + case ImProp_LineColor : LineColor = v; return; + case ImProp_FillColor : FillColor = v; return; + } + } +}; + // Double precision version of ImVec2 used by ImPlot. Extensible by end users. IM_MSVC_RUNTIME_CHECKS_OFF struct ImPlotPoint { @@ -511,17 +564,6 @@ struct ImPlotRect { // 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 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 @@ -540,6 +582,8 @@ struct ImPlotStyle { 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 DigitalBitHeight; // = 8, digital channels bit height (at y = 1.0f) in pixels + float DigitalBitGap; // = 4, digital channels bit padding gap in pixels // style colors ImVec4 Colors[ImPlotCol_COUNT]; // Array of styling colors. Indexable with ImPlotCol_ enums. // colormap @@ -859,76 +903,76 @@ 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). #ifdef IMGUI_HAS_TEXTURES -IMPLOT_API void PlotImage(const char* label_id, ImTextureRef tex_ref, 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, ImTextureRef tex_ref, 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()); #else -IMPLOT_API void PlotImage(const char* label_id, ImTextureID tex_ref, 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 tex_ref, 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()); #endif // 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 @@ -1058,35 +1102,18 @@ 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). +// 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(); @@ -1118,21 +1145,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(); diff --git a/implot_demo.cpp b/implot_demo.cpp index 990b1a26..4d2952e7 100644 --- a/implot_demo.cpp +++ b/implot_demo.cpp @@ -302,8 +302,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(); } } @@ -347,11 +349,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); @@ -375,18 +378,16 @@ 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::SetupLegend(ImPlotLocation_NorthWest, ImPlotLegendFlags_Reverse); // reverse legend to match vertical order on plot - 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(); } } @@ -408,10 +409,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(); } } @@ -429,18 +433,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_Circle; + ImPlot::PlotStairs("Post Step (default)", ys1, 21, 0.05f, 0, spec); + + spec.Flags = flags|ImPlotStairsFlags_PreStep; + spec.FillAlpha = 0.25f; + spec.Marker = ImPlotMarker_Circle; + ImPlot::PlotStairs("Pre Step", ys2, 21, 0.05f, 0, spec); ImPlot::EndPlot(); } @@ -452,7 +457,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(); } } @@ -487,12 +492,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(); } @@ -537,10 +542,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(); @@ -561,17 +567,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::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(); } } @@ -589,8 +600,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(); } } @@ -602,7 +612,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(); } } @@ -622,7 +632,7 @@ void Demo_PieCharts() { if (ImPlot::BeginPlot("##Pie1", ImVec2(ImGui::GetTextLineHeight()*16,ImGui::GetTextLineHeight()*16), 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(); } @@ -635,7 +645,7 @@ void Demo_PieCharts() { if (ImPlot::BeginPlot("##Pie2", ImVec2(ImGui::GetTextLineHeight()*16,ImGui::GetTextLineHeight()*16), 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(); @@ -683,7 +693,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(); @@ -761,8 +771,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); @@ -794,7 +806,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(); @@ -845,14 +857,21 @@ void Demo_DigitalPlots() { for (int i = 0; i < 2; ++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) + }); } } 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(); @@ -918,17 +937,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,ImGui::GetTextLineHeight()*10))) { 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(); } } @@ -936,10 +963,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; + 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)) { @@ -952,8 +978,9 @@ 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.Marker = m; + spec.FillAlpha = 1.0f; + ImPlot::PlotLine("##Filled", xs, ys, 2, spec); ImGui::PopID(); ys[0]--; ys[1]--; } @@ -961,8 +988,9 @@ 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.Marker = m; + spec.FillAlpha = 0.0f; + ImPlot::PlotLine("##Open", xs, ys, 2, spec); ImGui::PopID(); ys[0]--; ys[1]--; } @@ -971,7 +999,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(); @@ -996,8 +1024,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(); } @@ -1079,7 +1109,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); @@ -1304,12 +1334,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(); } } @@ -1464,12 +1495,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(); } } @@ -1502,8 +1543,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(); } } @@ -1613,14 +1653,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(); @@ -1631,8 +1676,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)); } @@ -1771,8 +1815,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)); @@ -1816,8 +1863,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)) { @@ -1931,7 +1981,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(); @@ -1954,7 +2004,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); @@ -1964,9 +2014,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 lambda = [](void* data, int idx) { ... return ImPlotPoint(x,y); }; @@ -2090,18 +2138,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"); @@ -2352,9 +2411,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(); @@ -2365,11 +2428,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); @@ -2380,20 +2438,11 @@ 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.PlotBorderSize = 0; style.MinorAlpha = 1.0f; style.MajorTickLen = ImVec2(0,0); @@ -2407,6 +2456,8 @@ void StyleSeaborn() { style.LegendPadding = ImVec2(5,5); style.MousePosPadding = ImVec2(5,5); style.PlotMinSize = ImVec2(300,225); + style.DigitalBitHeight = 8; + style.DigitalBitGap = 4; } } // namespace MyImPlot diff --git a/implot_internal.h b/implot_internal.h index 46dfaa5e..b540c1bc 100644 --- a/implot_internal.h +++ b/implot_internal.h @@ -1194,30 +1194,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; + float DigitalBitHeight; // TODO: remove + float DigitalBitGap; // TODO: remove bool RenderLine; bool RenderFill; - bool RenderMarkerLine; - bool RenderMarkerFill; 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; } }; @@ -1330,14 +1318,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& label_col = IMPLOT_AUTO_COL); // 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& label_col = IMPLOT_AUTO_COL) { + if (BeginItem(label_id, spec, label_col)) { 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; } diff --git a/implot_items.cpp b/implot_items.cpp index af03bf16..a8a0c350 100644 --- a/implot_items.cpp +++ b/implot_items.cpp @@ -119,7 +119,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); @@ -323,34 +328,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) @@ -396,28 +373,20 @@ static const float ITEM_HIGHLIGHT_LINE_SCALE = 2.0f; static const 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& label_col) { 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(label_col)) + item->Color = ImGui::ColorConvertFloat4ToU32(label_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; @@ -431,32 +400,20 @@ 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; + // SPEC-TODO: remove + s.DigitalBitHeight = gp.Style.DigitalBitHeight; + s.DigitalBitGap = gp.Style.DigitalBitGap; // 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) @@ -466,10 +423,8 @@ 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; // push rendering clip rect PushPlotClipRect(); return true; @@ -1571,74 +1526,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)) { 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.Spec.Marker != ImPlotMarker_None) { + 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); } //----------------------------------------------------------------------------- @@ -1646,49 +1601,49 @@ 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) { + if (BeginItemEx(label_id, Fitter1(getter), spec, spec.LineColor)) { if (getter.Count <= 0) { EndItem(); return; } const ImPlotNextItemData& s = GetItemData(); - ImPlotMarker marker = s.Marker == ImPlotMarker_None ? ImPlotMarker_Circle: s.Marker; + ImPlotMarker marker = s.Spec.Marker == ImPlotMarker_None ? ImPlotMarker_Circle: s.Spec.Marker; if (marker != ImPlotMarker_None) { - if (ImHasFlag(flags,ImPlotScatterFlags_NoClip)) { + 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, 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); } //----------------------------------------------------------------------------- @@ -1696,63 +1651,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)) { 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.Spec.Marker != ImPlotMarker_None) { 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); } //----------------------------------------------------------------------------- @@ -1760,15 +1715,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(); @@ -1776,47 +1731,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); } //----------------------------------------------------------------------------- @@ -1824,15 +1779,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) { @@ -1841,22 +1796,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) { @@ -1865,56 +1820,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); } } @@ -1923,9 +1878,11 @@ 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) { + 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; @@ -1956,7 +1913,7 @@ 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 { @@ -1978,28 +1935,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 @@ -2008,24 +1966,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); + 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(); @@ -2033,24 +1991,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); + 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(); @@ -2058,36 +2016,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 @@ -2096,8 +2054,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)) { if (getter_mark.Count <= 0 || getter_base.Count <= 0) { EndItem(); return; @@ -2105,52 +2063,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.Spec.Marker != ImPlotMarker_None) { 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 @@ -2160,40 +2118,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 @@ -2278,12 +2236,12 @@ double PieChartSum(const T* values, int count, bool ignore_hidden) { } 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[], const T* values, int count, ImPlotPoint center, double radius, double angle0, const ImPlotSpec& spec) { ImDrawList& draw_list = *GetPlotDrawList(); - const bool ignore_hidden = ImHasFlag(flags, ImPlotPieChartFlags_IgnoreHidden); + const bool ignore_hidden = ImHasFlag(spec.Flags, ImPlotPieChartFlags_IgnoreHidden); const double sum = PieChartSum(values, count, ignore_hidden); - const bool normalize = ImHasFlag(flags, ImPlotPieChartFlags_Normalize) || sum > 1.0; + 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; @@ -2296,7 +2254,7 @@ void PlotPieChartEx(const char* const label_ids[], const T* values, int count, I 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)) { const bool hovered = ImPlot::IsLegendEntryHovered(label_ids[i]) && ImHasFlag(flags, ImPlotPieChartFlags_Exploding); if (sum > 0.0) { ImU32 col = GetCurrentItem()->Color; @@ -2321,25 +2279,25 @@ 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 bool ignore_hidden = ImHasFlag(spec.Flags, ImPlotPieChartFlags_IgnoreHidden); const double sum = PieChartSum(values, count, ignore_hidden); - const bool normalize = ImHasFlag(flags, ImPlotPieChartFlags_Normalize) || sum > 1.0; + 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, values, count, center, radius, angle0, spec); if (fmt != nullptr) { double a0 = angle0 * 2 * IM_PI / 360.0; double a1 = angle0 * 2 * IM_PI / 360.0; @@ -2369,7 +2327,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 @@ -2520,19 +2478,19 @@ 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); + const bool col_maj = ImHasFlag(spec.Flags, ImPlotHeatmapFlags_ColMajor); RenderHeatmap(draw_list, values, 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 @@ -2541,11 +2499,11 @@ 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(flags, ImPlotHistogramFlags_Cumulative); - const bool density = ImHasFlag(flags, ImPlotHistogramFlags_Density); - const bool outliers = !ImHasFlag(flags, ImPlotHistogramFlags_NoOutliers); + const bool cumulative = ImHasFlag(spec.Flags, ImPlotHistogramFlags_Cumulative); + const bool density = ImHasFlag(spec.Flags, ImPlotHistogramFlags_Density); + const bool outliers = !ImHasFlag(spec.Flags, ImPlotHistogramFlags_NoOutliers); if (count <= 0 || bins == 0) return 0; @@ -2612,13 +2570,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 @@ -2627,12 +2590,12 @@ 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); if (count <= 0 || x_bins == 0 || y_bins == 0) return 0; @@ -2689,7 +2652,7 @@ 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; @@ -2700,7 +2663,7 @@ double PlotHistogram2D(const char* label_id, const T* xs, const T* ys, int count } 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 @@ -2711,8 +2674,8 @@ CALL_INSTANTIATE_FOR_NUMERIC_TYPES() // TODO: Make this behave like all the other plot types (.e. not fixed in y axis) 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(); @@ -2730,7 +2693,7 @@ void PlotDigitalEx(const char* label_id, Getter getter, ImPlotDigitalFlags flags continue; } if (ImNanOrInf(itemData2.y)) itemData2.y = ImConstrainNan(ImConstrainInf(itemData2.y)); - int pixY_0 = (int)(s.LineWeight); + int pixY_0 = (int)(s.Spec.LineWeight); itemData1.y = ImMax(0.0, itemData1.y); const float pixY_1 = s.DigitalBitHeight * (float)itemData1.y; const int pixY_chPosOffset = (int)(ImMax(s.DigitalBitHeight, pixY_1) + s.DigitalBitGap); @@ -2757,7 +2720,7 @@ void PlotDigitalEx(const char* label_id, Getter getter, ImPlotDigitalFlags flags if ((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; } @@ -2770,18 +2733,18 @@ 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); } //----------------------------------------------------------------------------- @@ -2789,11 +2752,11 @@ void PlotDigitalG(const char* label_id, ImPlotGetter getter_func, void* data, in //----------------------------------------------------------------------------- #ifdef IMGUI_HAS_TEXTURES -void PlotImage(const char* label_id, ImTextureRef tex_ref, const ImPlotPoint& bmin, const ImPlotPoint& bmax, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& tint_col, ImPlotImageFlags) { +void PlotImage(const char* label_id, ImTextureRef tex_ref, const ImPlotPoint& bmin, const ImPlotPoint& bmax, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& tint_col, const ImPlotSpec& spec) { #else -void PlotImage(const char* label_id, ImTextureID tex_ref, const ImPlotPoint& bmin, const ImPlotPoint& bmax, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& tint_col, ImPlotImageFlags) { +void PlotImage(const char* label_id, ImTextureID tex_ref, const ImPlotPoint& bmin, const ImPlotPoint& bmax, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& tint_col, const ImPlotSpec& spec) { #endif - if (BeginItemEx(label_id, FitterRect(bmin,bmax))) { + if (BeginItemEx(label_id, FitterRect(bmin,bmax), spec)) { ImU32 tint_col32 = ImGui::ColorConvertFloat4ToU32(tint_col); GetCurrentItem()->Color = tint_col32; ImDrawList& draw_list = *GetPlotDrawList(); @@ -2810,17 +2773,17 @@ void PlotImage(const char* label_id, ImTextureID tex_ref, const ImPlotPoint& bmi // [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)); } @@ -2829,7 +2792,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)); } @@ -2842,8 +2805,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(); } From 47ece5d58418bd047d8af6f4e1a8d83bae265839 Mon Sep 17 00:00:00 2001 From: epezent Date: Sat, 30 Sep 2023 11:33:52 -0500 Subject: [PATCH 02/21] Make markers automatically cycle; adopt constexpr --- implot.cpp | 53 +++++++++++++++++------------- implot.h | 19 +++++++---- implot_demo.cpp | 10 +++--- implot_internal.h | 42 +++++++++++++++--------- implot_items.cpp | 82 ++++++++++++++++++++++++++++------------------- 5 files changed, 123 insertions(+), 83 deletions(-) diff --git a/implot.cpp b/implot.cpp index db5d5504..09d1ca42 100644 --- a/implot.cpp +++ b/implot.cpp @@ -240,6 +240,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"; @@ -697,8 +698,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) @@ -834,7 +835,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, @@ -846,7 +847,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; @@ -866,28 +867,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; @@ -1803,8 +1804,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) { @@ -3251,9 +3252,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; @@ -3881,7 +3882,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"); @@ -4468,6 +4469,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 //------------------------------------------------------------------------------ @@ -4541,7 +4550,7 @@ ImU32 NextColormapColorU32() { ImVec4 NextColormapColor() { return ImGui::ColorConvertU32ToFloat4(NextColormapColorU32()); -} +} int GetColormapSize(ImPlotColormap cmap) { ImPlotContext& gp = *GImPlot; @@ -5299,7 +5308,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"); diff --git a/implot.h b/implot.h index 72712864..e974e3fc 100644 --- a/implot.h +++ b/implot.h @@ -65,13 +65,14 @@ #define IMPLOT_VERSION "0.17 WIP" // ImPlot version integer encoded as XYYZZ (X=major, YY=minor, ZZ=patch). #define IMPLOT_VERSION_NUM 1700 -// 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 //----------------------------------------------------------------------------- @@ -413,7 +414,8 @@ enum ImPlotScale_ { // 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 @@ -1153,7 +1155,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 //----------------------------------------------------------------------------- @@ -1223,7 +1228,7 @@ IMPLOT_API void BustColorCache(const char* plot_title_id = nullptr); //----------------------------------------------------------------------------- // [SECTION] Input Mapping //----------------------------------------------------------------------------- - + // Provides access to input mapping structure for permanent modifications to controls for pan, select, etc. IMPLOT_API ImPlotInputMap& GetInputMap(); diff --git a/implot_demo.cpp b/implot_demo.cpp index 4d2952e7..517831ef 100644 --- a/implot_demo.cpp +++ b/implot_demo.cpp @@ -439,12 +439,12 @@ void Demo_StairstepPlots() { ImPlotSpec spec; spec.Flags = flags; spec.FillAlpha = 0.25f; - spec.Marker = ImPlotMarker_Circle; + 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_Circle; + spec.Marker = ImPlotMarker_Auto; ImPlot::PlotStairs("Pre Step", ys2, 21, 0.05f, 0, spec); ImPlot::EndPlot(); @@ -581,7 +581,7 @@ void Demo_ErrorBars() { 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::PlotScatter("Scatter", xs, lin2, 5); ImPlot::EndPlot(); } @@ -963,7 +963,7 @@ void Demo_RealtimePlots() { //----------------------------------------------------------------------------- void Demo_MarkersAndText() { - static ImPlotSpec spec; + 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"); @@ -978,7 +978,6 @@ void Demo_MarkersAndText() { // filled markers for (int m = 0; m < ImPlotMarker_COUNT; ++m) { ImGui::PushID(m); - spec.Marker = m; spec.FillAlpha = 1.0f; ImPlot::PlotLine("##Filled", xs, ys, 2, spec); ImGui::PopID(); @@ -988,7 +987,6 @@ void Demo_MarkersAndText() { // open markers for (int m = 0; m < ImPlotMarker_COUNT; ++m) { ImGui::PushID(m); - spec.Marker = m; spec.FillAlpha = 0.0f; ImPlot::PlotLine("##Open", xs, ys, 2, spec); ImGui::PopID(); diff --git a/implot_internal.h b/implot_internal.h index b540c1bc..a602f669 100644 --- a/implot_internal.h +++ b/implot_internal.h @@ -53,21 +53,24 @@ // to ImPlotStyleVar_ over time. // Minimum allowable timestamp value 01/01/1970 @ 12:00am (UTC) (DO NOT DECREASE THIS) -#define IMPLOT_MIN_TIME 0 +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); \ @@ -227,9 +230,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 @@ -265,6 +269,10 @@ enum ImPlotTimeFmt_ { // default [ 24 Hour Clock ] ImPlotTimeFmt_Hr // 7pm [ 19:00 ] }; +enum ImPlotMarkerInternal_ { + ImPlotMarker_Invalid = -3 +}; + //----------------------------------------------------------------------------- // [SECTION] Callbacks //----------------------------------------------------------------------------- @@ -962,6 +970,7 @@ struct ImPlotItem { ImGuiID ID; ImU32 Color; + ImPlotMarker Marker; ImRect LegendHoverRect; int NameOffset; bool Show; @@ -971,6 +980,7 @@ struct ImPlotItem ImPlotItem() { ID = 0; Color = IM_COL32_WHITE; + Marker = ImPlotMarker_None; NameOffset = -1; Show = true; SeenThisFrame = false; @@ -1014,8 +1024,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 */ } @@ -1199,6 +1210,7 @@ struct ImPlotNextItemData { float DigitalBitGap; // TODO: remove bool RenderLine; bool RenderFill; + bool RenderMarkers; bool HasHidden; bool Hidden; ImPlotCond HiddenCond; @@ -1318,12 +1330,12 @@ 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, const ImPlotSpec& spec = ImPlotSpec(), const ImVec4& label_col = IMPLOT_AUTO_COL); +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, const ImPlotSpec& spec, const ImVec4& label_col = IMPLOT_AUTO_COL) { - if (BeginItem(label_id, spec, label_col)) { +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(spec.Flags, ImPlotItemFlags_NoFit)) fitter.Fit(plot.Axes[plot.CurrentX], plot.Axes[plot.CurrentY]); @@ -1556,7 +1568,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 a8a0c350..cf1c475e 100644 --- a/implot_items.cpp +++ b/implot_items.cpp @@ -369,11 +369,11 @@ 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, const ImPlotSpec& spec, const ImVec4& label_col) { +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(); @@ -383,14 +383,27 @@ bool BeginItem(const char* label_id, const ImPlotSpec& spec, const ImVec4& label gp.CurrentItem = item; ImPlotNextItemData& s = gp.NextItemData; // set/override item color - if (!IsColorAuto(label_col)) - item->Color = ImGui::ColorConvertFloat4ToU32(label_col); + if (!IsColorAuto(item_col)) + item->Color = ImGui::ColorConvertFloat4ToU32(item_col); else if (just_created) item->Color = NextColormapColorU32(); 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(); @@ -405,6 +418,7 @@ bool BeginItem(const char* label_id, const ImPlotSpec& spec, const ImVec4& label 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; // SPEC-TODO: remove s.DigitalBitHeight = gp.Style.DigitalBitHeight; s.DigitalBitGap = gp.Style.DigitalBitGap; @@ -425,6 +439,7 @@ bool BeginItem(const char* label_id, const ImPlotSpec& spec, const ImVec4& label // set render flags 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; @@ -1452,15 +1467,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), @@ -1482,15 +1497,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) { @@ -1527,7 +1542,7 @@ void RenderMarkers(const _Getter& getter, ImPlotMarker marker, float size, bool template void PlotLineEx(const char* label_id, const _Getter& getter, const ImPlotSpec& spec) { - if (BeginItemEx(label_id, Fitter1<_Getter>(getter), spec, spec.LineColor)) { + if (BeginItemEx(label_id, Fitter1<_Getter>(getter), spec, spec.LineColor, spec.Marker)) { if (getter.Count <= 0) { EndItem(); return; @@ -1559,7 +1574,7 @@ void PlotLineEx(const char* label_id, const _Getter& getter, const ImPlotSpec& s } } // render markers - if (s.Spec.Marker != ImPlotMarker_None) { + if (s.RenderMarkers) { if (ImHasFlag(spec.Flags, ImPlotLineFlags_NoClip)) { PopPlotClipRect(); PushPlotClipRect(s.Spec.Size); @@ -1602,21 +1617,22 @@ void PlotLineG(const char* label_id, ImPlotGetter getter_func, void* data, int c template void PlotScatterEx(const char* label_id, const Getter& getter, const ImPlotSpec& spec) { - if (BeginItemEx(label_id, Fitter1(getter), spec, spec.LineColor)) { + // 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.Spec.Marker == ImPlotMarker_None ? ImPlotMarker_Circle: s.Spec.Marker; - if (marker != ImPlotMarker_None) { + if (s.RenderMarkers) { if (ImHasFlag(spec.Flags,ImPlotScatterFlags_NoClip)) { PopPlotClipRect(); PushPlotClipRect(s.Spec.Size); } const ImU32 col_line = ImGui::GetColorU32(s.Spec.LineColor); const ImU32 col_fill = ImGui::GetColorU32(s.Spec.FillColor); - RenderMarkers(getter, marker, s.Spec.Size, s.RenderFill, col_fill, s.RenderLine, col_line, s.Spec.LineWeight); + RenderMarkers(getter, s.Spec.Marker, s.Spec.Size, s.RenderFill, col_fill, s.RenderLine, col_line, s.Spec.LineWeight); } EndItem(); } @@ -1652,7 +1668,7 @@ void PlotScatterG(const char* label_id, ImPlotGetter getter_func, void* data, in template void PlotStairsEx(const char* label_id, const Getter& getter, const ImPlotSpec& spec) { - if (BeginItemEx(label_id, Fitter1(getter), spec, spec.LineColor)) { + if (BeginItemEx(label_id, Fitter1(getter), spec, spec.LineColor, spec.Marker)) { if (getter.Count <= 0) { EndItem(); return; @@ -1675,7 +1691,7 @@ void PlotStairsEx(const char* label_id, const Getter& getter, const ImPlotSpec& } } // render markers - if (s.Spec.Marker != ImPlotMarker_None) { + if (s.RenderMarkers) { PopPlotClipRect(); PushPlotClipRect(s.Spec.Size); const ImU32 col_line = ImGui::GetColorU32(s.Spec.LineColor); @@ -2055,7 +2071,7 @@ CALL_INSTANTIATE_FOR_NUMERIC_TYPES() template 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)) { + 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; @@ -2067,7 +2083,7 @@ void PlotStemsEx(const char* label_id, const _GetterM& getter_mark, const _Gette RenderPrimitives2(getter_mark, getter_base, col_line, s.Spec.LineWeight); } // render markers - if (s.Spec.Marker != ImPlotMarker_None) { + if (s.RenderMarkers) { PopPlotClipRect(); PushPlotClipRect(s.Spec.Size); const ImU32 col_line = ImGui::GetColorU32(s.Spec.LineColor); From 2ba8a2d7c4585d78a00b0686be7fafbcd28b3d7a Mon Sep 17 00:00:00 2001 From: epezent Date: Sat, 30 Sep 2023 14:29:03 -0500 Subject: [PATCH 03/21] Make remaining applicable PlotX functions honor offset/stride; docs; typos; --- implot.h | 89 ++++++++-------- implot_internal.h | 44 ++++---- implot_items.cpp | 260 ++++++++++++++++++++++++---------------------- 3 files changed, 210 insertions(+), 183 deletions(-) diff --git a/implot.h b/implot.h index e974e3fc..f4d586d5 100644 --- a/implot.h +++ b/implot.h @@ -47,6 +47,7 @@ #pragma once #include "imgui.h" +#include "imgui_internal.h" #ifndef IMGUI_DISABLE //----------------------------------------------------------------------------- @@ -133,7 +134,7 @@ enum ImAxis_ { ImAxis_COUNT }; -// Plotting properties +// Plotting properties. These provide syntactic sugar for creating ImPlotSpecs from ImProp,value pairs. enum ImProp_ { ImProp_LineColor, ImProp_LineWeight, @@ -239,14 +240,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 @@ -256,56 +257,56 @@ 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) @@ -313,13 +314,13 @@ enum ImPlotPieChartFlags_ { ImPlotPieChartFlags_Exploding = 1 << 12 // Explode legend-hovered slice }; -// 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) @@ -329,23 +330,23 @@ enum ImPlotHistogramFlags_ { 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 }; @@ -423,9 +424,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 }; @@ -470,37 +471,38 @@ enum ImPlotBin_ { ImPlotBin_Scott = -4, // w = 3.49 * sigma / cbrt(n) }; -// Plot item styling specification data -// TODO: merge with ImPlotNextItemData -// issues: -// - need to verify that stride offset work on functions previously not accepting them -// - next plot item data needed? - +// Plot item styling specification. Provide these to PlotX functions to override styling, specify +// offsetting or stride, or set optional flags. struct ImPlotSpec { - ImVec4 LineColor = IMPLOT_AUTO_COL; // line color (applies to line, bar edges, marker edges) - float LineWeight = 1.0f; // line weight in pixels (applies to lines, bar edges, marker edges) - ImVec4 FillColor = IMPLOT_AUTO_COL; // fill color (applies to bar faces and shaded regions) - float FillAlpha = 1.0f; // alpha multiplier (applies to FillColor) - ImPlotMarker Marker = ImPlotMarker_None; // marker type - float Size = 4; // size of markers (radius) and error bar whiskers (widget/height) in pixels - int Offset = 0; // data offset - int Stride = IMPLOT_AUTO; // data stride; defaults to sizeof(T) where T is the type passed to PlotX - ImPlotItemFlags Flags = 0; // item flags + 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 bar faces and shaded regions); 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) and error bar whiskers (widget/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 specific ImPlotXFlags where X corresponds + // with the PlotX function to which this is passed (e.g. ImPlotLineFlags is only compatible with PlotLine) 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, "Incorrect number of arguments!"); + 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) { @@ -513,14 +515,19 @@ struct ImPlotSpec { 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 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 ImProp which cannot be set from ImVec4 value!"); } }; @@ -786,7 +793,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); @@ -869,13 +876,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 diff --git a/implot_internal.h b/implot_internal.h index a602f669..c7a709a8 100644 --- a/implot_internal.h +++ b/implot_internal.h @@ -137,16 +137,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]; } @@ -154,16 +161,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) @@ -171,8 +178,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; @@ -180,6 +187,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 @@ -760,7 +768,7 @@ struct ImPlotAxis PickerTimeMin = ImPlotTime::FromDouble(Range.Min); UpdateTransformCache(); return true; - }; + } inline bool SetMax(double _max, bool force=false) { if (!force && IsLockedMax()) @@ -779,7 +787,7 @@ struct ImPlotAxis PickerTimeMax = ImPlotTime::FromDouble(Range.Max); UpdateTransformCache(); return true; - }; + } inline void SetRange(double v1, double v2) { Range.Min = ImMin(v1,v2); @@ -1538,8 +1546,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)); diff --git a/implot_items.cpp b/implot_items.cpp index cf1c475e..4f0fe85d 100644 --- a/implot_items.cpp +++ b/implot_items.cpp @@ -482,13 +482,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 @@ -500,29 +501,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; }; //----------------------------------------------------------------------------- @@ -531,13 +535,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 @@ -547,49 +552,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 @@ -603,7 +612,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), @@ -616,6 +625,7 @@ struct GetterError { const int Count; const int Offset; const int Stride; + typedef ImPlotPointError value_type; }; //----------------------------------------------------------------------------- @@ -627,7 +637,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); } @@ -640,7 +650,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); } } @@ -652,7 +662,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); } } @@ -664,12 +674,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); } @@ -688,8 +698,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); @@ -711,8 +721,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); @@ -842,13 +852,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; @@ -873,13 +883,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; @@ -910,8 +920,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); @@ -937,8 +947,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); @@ -965,8 +975,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); @@ -1003,8 +1013,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); @@ -1042,8 +1052,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); @@ -1082,8 +1092,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); @@ -1117,13 +1127,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; @@ -1148,13 +1158,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; @@ -1178,14 +1188,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))) { @@ -1210,14 +1220,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))) { @@ -1245,15 +1255,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; @@ -1314,7 +1324,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)))) @@ -1402,7 +1412,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; @@ -1446,7 +1456,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); @@ -1895,6 +1905,7 @@ 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, 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; @@ -1914,7 +1925,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; @@ -1936,7 +1947,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; @@ -1994,8 +2005,8 @@ void PlotErrorBarsVEx(const char* label_id, const _GetterPos& getter_pos, const 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); + 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.Spec.LineWeight); @@ -2019,8 +2030,8 @@ void PlotErrorBarsHEx(const char* label_id, const _GetterPos& getter_pos, const 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); + 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.Spec.LineWeight); @@ -2227,45 +2238,46 @@ 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, const ImPlotSpec& spec) { +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(spec.Flags, ImPlotPieChartFlags_IgnoreHidden); - const double sum = PieChartSum(values, count, ignore_hidden); + 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; @@ -2307,13 +2319,15 @@ void PlotPieChart(const char* const label_ids[], const T* values, int count, dou IM_ASSERT_USER_ERROR(GImPlot->CurrentPlot != nullptr, "PlotPieChart() needs to be called between BeginPlot() and EndPlot()!"); ImDrawList& draw_list = *GetPlotDrawList(); + IndexerIdx indexer(values,count,spec.Offset,Stride(spec)); + const bool ignore_hidden = ImHasFlag(spec.Flags, ImPlotPieChartFlags_IgnoreHidden); - const double sum = PieChartSum(values, count, ignore_hidden); + 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, spec); + 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; @@ -2322,13 +2336,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; const bool hovered = ImPlot::IsLegendEntryHovered(label_ids[i]) && ImHasFlag(flags, ImPlotPieChartFlags_Exploding); @@ -2351,10 +2365,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), @@ -2367,8 +2381,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)); @@ -2380,16 +2394,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), @@ -2402,8 +2417,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)); @@ -2415,21 +2430,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); @@ -2441,11 +2455,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 @@ -2462,9 +2476,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); @@ -2480,9 +2494,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); @@ -2502,7 +2516,8 @@ void PlotHeatmap(const char* label_id, const T* values, int rows, int cols, doub } ImDrawList& draw_list = *GetPlotDrawList(); const bool col_maj = ImHasFlag(spec.Flags, ImPlotHeatmapFlags_ColMajor); - RenderHeatmap(draw_list, values, rows, cols, scale_min, scale_max, fmt, bounds_min, bounds_max, true, col_maj); + 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(); } } @@ -2521,19 +2536,18 @@ double PlotHistogram(const char* label_id, const T* values, int count, int bins, const bool density = ImHasFlag(spec.Flags, ImPlotHistogramFlags_Density); const bool outliers = !ImHasFlag(spec.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; @@ -2551,7 +2565,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; @@ -2613,29 +2627,26 @@ double PlotHistogram2D(const char* label_id, const T* xs, const T* ys, int count 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; @@ -2651,9 +2662,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) @@ -2674,7 +2685,8 @@ double PlotHistogram2D(const char* label_id, const T* xs, const T* ys, int count 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; @@ -2701,9 +2713,9 @@ void PlotDigitalEx(const char* label_id, Getter getter, const ImPlotSpec& spec) 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; @@ -2723,7 +2735,7 @@ void PlotDigitalEx(const char* label_id, Getter getter, const ImPlotSpec& spec) //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++; From c129a61acbea611ee12e7820e0bf388676cd60fd Mon Sep 17 00:00:00 2001 From: epezent Date: Sun, 1 Oct 2023 21:54:11 -0500 Subject: [PATCH 04/21] remove DigitalBitHeight in favor of ImPlotSpec::Size; rename DigitalBitGap to DigitalSpacing --- implot.cpp | 18 +++++++----------- implot.h | 24 ++++++++++++------------ implot_demo.cpp | 20 ++++++++++++-------- implot_internal.h | 2 -- implot_items.cpp | 13 ++++++------- 5 files changed, 37 insertions(+), 40 deletions(-) diff --git a/implot.cpp b/implot.cpp index 09d1ca42..1a7287ae 100644 --- a/implot.cpp +++ b/implot.cpp @@ -178,7 +178,9 @@ ImPlotInputMap::ImPlotInputMap() { ImPlot::MapInputDefault(this); } -ImPlotStyle::ImPlotStyle() { +ImPlotStyle::ImPlotStyle() { + PlotDefaultSize = ImVec2(400,300); + PlotMinSize = ImVec2(200,150); PlotBorderSize = 1; MinorAlpha = 0.25f; MajorTickLen = ImVec2(10,10); @@ -195,10 +197,7 @@ ImPlotStyle::ImPlotStyle() { MousePosPadding = ImVec2(10,10); AnnotationPadding = ImVec2(2,2); FitPadding = ImVec2(0,0); - PlotDefaultSize = ImVec2(400,300); - PlotMinSize = ImVec2(200,150); - DigitalBitHeight = 8; - DigitalBitGap = 4; + DigitalSpacing = 4; ImPlot::StyleColorsAuto(this); @@ -305,7 +304,6 @@ static const ImPlotStyleVarInfo GPlotStyleVarInfo[] = { ImGuiDataType_Float, 2, (ImU32)offsetof(ImPlotStyle, MousePosPadding) }, // ImPlotStyleVar_MousePosPadding { ImGuiDataType_Float, 2, (ImU32)offsetof(ImPlotStyle, AnnotationPadding) }, // ImPlotStyleVar_AnnotationPadding { ImGuiDataType_Float, 2, (ImU32)offsetof(ImPlotStyle, FitPadding) }, // ImPlotStyleVar_FitPadding - { ImGuiDataType_Float, 2, (ImU32)offsetof(ImPlotStyle, DigitalPadding) }, // ImPlotStyleVar_DigitalPadding { ImGuiDataType_Float, 1, (ImU32)offsetof(ImPlotStyle, DigitalSpacing) }, // ImPlotStyleVar_DigitalSpacing }; @@ -4947,6 +4945,8 @@ void ShowStyleEditor(ImPlotStyle* ref) { if (ImGui::BeginTabBar("##StyleEditor")) { if (ImGui::BeginTabItem("Variables")) { 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"); @@ -4955,8 +4955,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"); @@ -4966,9 +4964,7 @@ 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::Text("Miscellaneous"); - ImGui::SliderFloat("DigitalBitHeight", &style.DigitalBitHeight, 0.0f, 20.0f, "%.1f"); - ImGui::SliderFloat("DigitalBitGap", &style.DigitalBitGap, 0.0f, 20.0f, "%.1f"); + ImGui::SliderFloat("DigitalSpacing", &style.DigitalSpacing, 0.0f, 20.0f, "%.1f"); ImGui::EndTabItem(); } if (ImGui::BeginTabItem("Colors")) { diff --git a/implot.h b/implot.h index f4d586d5..9b27a1d2 100644 --- a/implot.h +++ b/implot.h @@ -382,6 +382,8 @@ enum ImPlotCol_ { // Plot styling variables. enum ImPlotStyleVar_ { + 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 @@ -398,10 +400,7 @@ 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_DigitalBitHeight, // float, digital channels bit height (at 1) in pixels - ImPlotStyleVar_DigitalBitGap, // float, digital channels bit padding gap in pixels + ImPlotStyleVar_DigitalSpacing, // float, digital plots padding gap in pixels ImPlotStyleVar_COUNT }; @@ -479,7 +478,7 @@ struct ImPlotSpec { ImVec4 FillColor = IMPLOT_AUTO_COL; // fill color (applies to bar faces and shaded regions); 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) and error bar whiskers (widget/height) in pixels + 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 specific ImPlotXFlags where X corresponds @@ -517,7 +516,7 @@ struct ImPlotSpec { case ImProp_Flags : Flags = (ImPlotItemFlags)v; return; default: break; } - IM_ASSERT(0 && "User provided ImProp which cannot be set from scalar value!"); + IM_ASSERT(0 && "User provided an ImProp which cannot be set from scalar value!"); } // Set a property from an ImVec4 value. @@ -527,7 +526,7 @@ struct ImPlotSpec { case ImProp_FillColor : FillColor = v; return; default: break; } - IM_ASSERT(0 && "User provided ImProp which cannot be set from ImVec4 value!"); + IM_ASSERT(0 && "User provided an ImProp which cannot be set from ImVec4 value!"); } }; @@ -573,6 +572,9 @@ struct ImPlotRect { // Plot style structure struct ImPlotStyle { + // 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 @@ -581,6 +583,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 @@ -589,10 +592,7 @@ 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 DigitalBitHeight; // = 8, digital channels bit height (at y = 1.0f) in pixels - float DigitalBitGap; // = 4, digital channels bit padding gap in pixels + float DigitalSpacing; // = 4, digital plot padding gap in pixels // style colors ImVec4 Colors[ImPlotCol_COUNT]; // Array of styling colors. Indexable with ImPlotCol_ enums. // colormap @@ -755,7 +755,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(); //----------------------------------------------------------------------------- diff --git a/implot_demo.cpp b/implot_demo.cpp index 517831ef..16288a9d 100644 --- a/implot_demo.cpp +++ b/implot_demo.cpp @@ -823,14 +823,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]); @@ -844,6 +846,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)); @@ -854,12 +858,13 @@ 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(), { ImProp_Offset, dataDigital[i].Offset, - ImProp_Stride, 2 * sizeof(float) + ImProp_Stride, 2 * sizeof(float), + ImProp_Size, (i+1) * 4 }); } } @@ -2441,6 +2446,8 @@ void StyleSeaborn() { 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.MousePosPadding = ImVec2(5,5); + style.PlotMinSize = ImVec2(300,225); style.PlotBorderSize = 0; style.MinorAlpha = 1.0f; style.MajorTickLen = ImVec2(0,0); @@ -2452,10 +2459,7 @@ 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.DigitalBitHeight = 8; - style.DigitalBitGap = 4; + style.DigitalSpacing = 4; } } // namespace MyImPlot diff --git a/implot_internal.h b/implot_internal.h index c7a709a8..5c294ba7 100644 --- a/implot_internal.h +++ b/implot_internal.h @@ -1214,8 +1214,6 @@ struct ImPlotNextPlotData // Temporary data storage for upcoming item struct ImPlotNextItemData { ImPlotSpec Spec; - float DigitalBitHeight; // TODO: remove - float DigitalBitGap; // TODO: remove bool RenderLine; bool RenderFill; bool RenderMarkers; diff --git a/implot_items.cpp b/implot_items.cpp index 4f0fe85d..6a2db8fc 100644 --- a/implot_items.cpp +++ b/implot_items.cpp @@ -419,9 +419,6 @@ bool BeginItem(const char* label_id, const ImPlotSpec& spec, const ImVec4& item_ 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; - // SPEC-TODO: remove - s.DigitalBitHeight = gp.Style.DigitalBitHeight; - s.DigitalBitGap = gp.Style.DigitalBitGap; // apply highlight mods if (item->LegendHovered) { if (!ImHasFlag(gp.CurrentItems->Legend.Flags, ImPlotLegendFlags_NoHighlightItem)) { @@ -2700,6 +2697,7 @@ 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, const ImPlotSpec& spec) { @@ -2720,11 +2718,13 @@ void PlotDigitalEx(const char* label_id, Getter getter, const ImPlotSpec& spec) itemData1 = itemData2; continue; } - if (ImNanOrInf(itemData2.y)) itemData2.y = ImConstrainNan(ImConstrainInf(itemData2.y)); + if (ImNanOrInf(itemData2.y)) { + itemData2.y = ImConstrainNan(ImConstrainInf(itemData2.y)); + } int pixY_0 = (int)(s.Spec.LineWeight); itemData1.y = ImMax(0.0, itemData1.y); - const float pixY_1 = s.DigitalBitHeight * (float)itemData1.y; - const int pixY_chPosOffset = (int)(ImMax(s.DigitalBitHeight, pixY_1) + s.DigitalBitGap); + const float pixY_1 = s.Spec.Size * (float)itemData1.y; + const int pixY_chPosOffset = (int)(ImMax(s.Spec.Size, pixY_1) + s.Style.DigitalSpacing); pixYMax = ImMax(pixYMax, pixY_chPosOffset); ImVec2 pMin = PlotToPixels(itemData1,IMPLOT_AUTO,IMPLOT_AUTO); ImVec2 pMax = PlotToPixels(itemData2,IMPLOT_AUTO,IMPLOT_AUTO); @@ -2743,7 +2743,6 @@ void PlotDigitalEx(const char* label_id, Getter getter, const ImPlotSpec& spec) // do not extend plot outside plot range pMin.x = ImClamp(pMin.x, !x_axis.IsInverted() ? x_axis.PixelMin : x_axis.PixelMax, !x_axis.IsInverted() ? x_axis.PixelMax - 1 : x_axis.PixelMin - 1); pMax.x = ImClamp(pMax.x, !x_axis.IsInverted() ? x_axis.PixelMin : x_axis.PixelMax, !x_axis.IsInverted() ? x_axis.PixelMax - 1 : x_axis.PixelMin - 1); - //plot a rectangle that extends up to x2 with y1 height if ((gp.CurrentPlot->PlotRect.Contains(pMin) || gp.CurrentPlot->PlotRect.Contains(pMax))) { // ImVec4 colAlpha = item->Color; From c96f18f374481fb389fe72b2b4287f7d228bcc74 Mon Sep 17 00:00:00 2001 From: epezent Date: Mon, 2 Oct 2023 10:08:38 -0500 Subject: [PATCH 05/21] Add ImPlotStyle::DigitalPadding; add spec demo and docs --- implot.cpp | 9 ++++++--- implot.h | 26 +++++++++++++++++++++++--- implot_demo.cpp | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ implot_items.cpp | 2 +- 4 files changed, 78 insertions(+), 7 deletions(-) diff --git a/implot.cpp b/implot.cpp index 1a7287ae..2038e130 100644 --- a/implot.cpp +++ b/implot.cpp @@ -32,15 +32,15 @@ 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/09/29 (0.17) - ImPlotSpec was made the default and _only_ way of styling plot items. Therefore the following features were removed: +- 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 was 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/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. - 2022/06/19 (0.14) - The signature of ColormapScale has changed to accommodate a new ImPlotColormapScaleFlags parameter @@ -197,6 +197,7 @@ ImPlotStyle::ImPlotStyle() { MousePosPadding = ImVec2(10,10); AnnotationPadding = ImVec2(2,2); FitPadding = ImVec2(0,0); + DigitalPadding = 20; DigitalSpacing = 4; ImPlot::StyleColorsAuto(this); @@ -304,6 +305,7 @@ static const ImPlotStyleVarInfo GPlotStyleVarInfo[] = { ImGuiDataType_Float, 2, (ImU32)offsetof(ImPlotStyle, MousePosPadding) }, // ImPlotStyleVar_MousePosPadding { ImGuiDataType_Float, 2, (ImU32)offsetof(ImPlotStyle, AnnotationPadding) }, // ImPlotStyleVar_AnnotationPadding { ImGuiDataType_Float, 2, (ImU32)offsetof(ImPlotStyle, FitPadding) }, // ImPlotStyleVar_FitPadding + { ImGuiDataType_Float, 1, (ImU32)offsetof(ImPlotStyle, DigitalPadding) }, // ImPlotStyleVar_DigitalPadding { ImGuiDataType_Float, 1, (ImU32)offsetof(ImPlotStyle, DigitalSpacing) }, // ImPlotStyleVar_DigitalSpacing }; @@ -4964,7 +4966,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("DigitalSpacing", &style.DigitalSpacing, 0.0f, 20.0f, "%.1f"); + 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")) { diff --git a/implot.h b/implot.h index 9b27a1d2..2ed5b6b8 100644 --- a/implot.h +++ b/implot.h @@ -400,7 +400,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_DigitalSpacing, // float, digital plots padding gap in pixels + ImPlotStyleVar_DigitalPadding, // float, digital plot padding from bottom in pixels + ImPlotStyleVar_DigitalSpacing, // float, digital plot spacing gap in pixels ImPlotStyleVar_COUNT }; @@ -471,7 +472,25 @@ enum ImPlotBin_ { }; // Plot item styling specification. Provide these to PlotX functions to override styling, specify -// offsetting or stride, or set optional flags. +// 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) @@ -592,7 +611,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) - float DigitalSpacing; // = 4, digital plot padding gap in pixels + 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 diff --git a/implot_demo.cpp b/implot_demo.cpp index 16288a9d..c13a7152 100644 --- a/implot_demo.cpp +++ b/implot_demo.cpp @@ -1959,6 +1959,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; @@ -2349,6 +2395,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); @@ -2459,6 +2506,7 @@ void StyleSeaborn() { style.PlotPadding = ImVec2(12,12); style.LabelPadding = ImVec2(5,5); style.LegendPadding = ImVec2(5,5); + style.DigitalPadding = 20; style.DigitalSpacing = 4; } diff --git a/implot_items.cpp b/implot_items.cpp index 6a2db8fc..b31e3a5d 100644 --- a/implot_items.cpp +++ b/implot_items.cpp @@ -2728,7 +2728,7 @@ void PlotDigitalEx(const char* label_id, Getter getter, const ImPlotSpec& spec) pixYMax = ImMax(pixYMax, pixY_chPosOffset); ImVec2 pMin = PlotToPixels(itemData1,IMPLOT_AUTO,IMPLOT_AUTO); ImVec2 pMax = PlotToPixels(itemData2,IMPLOT_AUTO,IMPLOT_AUTO); - const int pixY_Offset = 0; //20 pixel from bottom due to mouse cursor label + const int pixY_Offset = (int)gp.Style.DigitalPadding; const float y_ref = y_axis.IsInverted() ? y_axis.PixelMax : y_axis.PixelMin; pMin.y = y_ref - (gp.DigitalPlotOffset + pixY_Offset); pMax.y = y_ref - (gp.DigitalPlotOffset + pixY_0 + (int)pixY_1 + pixY_Offset); From b844d9680395472b4e3a9604ba817d448fd4d2a3 Mon Sep 17 00:00:00 2001 From: epezent Date: Mon, 2 Oct 2023 10:37:53 -0500 Subject: [PATCH 06/21] more doc additions/corrections --- implot.h | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/implot.h b/implot.h index 2ed5b6b8..086d6047 100644 --- a/implot.h +++ b/implot.h @@ -134,17 +134,17 @@ enum ImAxis_ { ImAxis_COUNT }; -// Plotting properties. These provide syntactic sugar for creating ImPlotSpecs from ImProp,value pairs. +// Plotting properties. These provide syntactic sugar for creating ImPlotSpecs from ImProp,value pairs. See ImPlotSpec documentation. enum ImProp_ { - ImProp_LineColor, - ImProp_LineWeight, - ImProp_FillColor, - ImProp_FillAlpha, - ImProp_Marker, - ImProp_Size, - ImProp_Offset, - ImProp_Stride, - ImProp_Flags + 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). @@ -494,14 +494,13 @@ enum ImPlotBin_ { 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 bar faces and shaded regions); IMPLOT_AUTO_COL will use next Colormap color or current item color + 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 specific ImPlotXFlags where X corresponds - // with the PlotX function to which this is passed (e.g. ImPlotLineFlags is only compatible with PlotLine) + ImPlotItemFlags Flags = ImPlotItemFlags_None; // optional item flags; can be composed from common ImPlotItemFlags and/or specialized ImPlotXFlags ImPlotSpec() { } From c353f238a5b19848f823e64f1660dae384aec360 Mon Sep 17 00:00:00 2001 From: epezent Date: Mon, 2 Oct 2023 11:23:43 -0500 Subject: [PATCH 07/21] make ImPlotPoint::Clamp const --- implot.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/implot.h b/implot.h index 086d6047..46dab0da 100644 --- a/implot.h +++ b/implot.h @@ -582,8 +582,8 @@ struct ImPlotRect { IMPLOT_API bool Contains(const ImPlotPoint& p) const { return Contains(p.x, p.y); } IMPLOT_API bool Contains(double x, double y) const { return X.Contains(x) && Y.Contains(y); } IMPLOT_API ImPlotPoint Size() const { return ImPlotPoint(X.Size(), Y.Size()); } - IMPLOT_API ImPlotPoint Clamp(const ImPlotPoint& p) { return Clamp(p.x, p.y); } - IMPLOT_API ImPlotPoint Clamp(double x, double y) { return ImPlotPoint(X.Clamp(x),Y.Clamp(y)); } + IMPLOT_API ImPlotPoint Clamp(const ImPlotPoint& p) const { return Clamp(p.x, p.y); } + IMPLOT_API ImPlotPoint Clamp(double x, double y) const { return ImPlotPoint(X.Clamp(x),Y.Clamp(y)); } IMPLOT_API ImPlotPoint Min() const { return ImPlotPoint(X.Min, Y.Min); } IMPLOT_API ImPlotPoint Max() const { return ImPlotPoint(X.Max, Y.Max); } }; From d689156850ec60436574b2532263322b440cba54 Mon Sep 17 00:00:00 2001 From: epezent Date: Mon, 2 Oct 2023 11:41:00 -0500 Subject: [PATCH 08/21] ImPlotNextItemData HiddenCond reset --- implot_internal.h | 1 + 1 file changed, 1 insertion(+) diff --git a/implot_internal.h b/implot_internal.h index 5c294ba7..5bdf98d4 100644 --- a/implot_internal.h +++ b/implot_internal.h @@ -1224,6 +1224,7 @@ struct ImPlotNextItemData { void Reset() { Spec = ImPlotSpec(); HasHidden = Hidden = false; + HiddenCond = ImPlotCond_None; } }; From e8baaa16b0771dfd457917db10be56d0cbb61107 Mon Sep 17 00:00:00 2001 From: Breno Cunha Queiroz Date: Sun, 30 Nov 2025 22:24:14 +0100 Subject: [PATCH 09/21] fix: compilation error after rebase --- implot.cpp | 2 +- implot_items.cpp | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/implot.cpp b/implot.cpp index 2038e130..a205c29f 100644 --- a/implot.cpp +++ b/implot.cpp @@ -288,7 +288,7 @@ struct ImPlotStyleVarInfo { static const ImPlotStyleVarInfo GPlotStyleVarInfo[] = { { ImGuiDataType_Float, 2, (ImU32)offsetof(ImPlotStyle, PlotDefaultSize) }, // ImPlotStyleVar_PlotDefaultSize - { ImGuiDataType_Float, 2, (ImU32)offsetof(ImPlotStyle, PlotMinSize) } // ImPlotStyleVar_PlotMinSize + { ImGuiDataType_Float, 2, (ImU32)offsetof(ImPlotStyle, PlotMinSize) }, // ImPlotStyleVar_PlotMinSize { ImGuiDataType_Float, 1, (ImU32)offsetof(ImPlotStyle, PlotBorderSize) }, // ImPlotStyleVar_PlotBorderSize { ImGuiDataType_Float, 1, (ImU32)offsetof(ImPlotStyle, MinorAlpha) }, // ImPlotStyleVar_MinorAlpha { ImGuiDataType_Float, 2, (ImU32)offsetof(ImPlotStyle, MajorTickLen) }, // ImPlotStyleVar_MajorTickLen diff --git a/implot_items.cpp b/implot_items.cpp index b31e3a5d..eb253a0b 100644 --- a/implot_items.cpp +++ b/implot_items.cpp @@ -2280,7 +2280,7 @@ void PlotPieChartEx(const char* const label_ids[], IndexerIdx indexer, ImPlot a1 = a0 + 2 * IM_PI * percent; if (BeginItemEx(label_ids[i], FitterRect(Pmin, Pmax), spec)) { - const bool hovered = ImPlot::IsLegendEntryHovered(label_ids[i]) && ImHasFlag(flags, ImPlotPieChartFlags_Exploding); + const bool hovered = ImPlot::IsLegendEntryHovered(label_ids[i]) && ImHasFlag(spec.Flags, ImPlotPieChartFlags_Exploding); if (sum > 0.0) { ImU32 col = GetCurrentItem()->Color; if (percent < 0.5) { @@ -2342,7 +2342,7 @@ void PlotPieChart(const char* const label_ids[], const T* values, int count, dou fmt((double)indexer[i], buffer, 32, fmt_data); ImVec2 size = ImGui::CalcTextSize(buffer); double angle = a0 + (a1 - a0) * 0.5; - const bool hovered = ImPlot::IsLegendEntryHovered(label_ids[i]) && ImHasFlag(flags, ImPlotPieChartFlags_Exploding); + const bool hovered = ImPlot::IsLegendEntryHovered(label_ids[i]) && ImHasFlag(spec.Flags, ImPlotPieChartFlags_Exploding); const double offset = (hovered ? 0.6 : 0.5) * radius; ImVec2 pos = PlotToPixels(center.x + offset * cos(angle), center.y + offset * sin(angle), IMPLOT_AUTO, IMPLOT_AUTO); ImU32 col = CalcTextColor(ImGui::ColorConvertU32ToFloat4(item->Color)); @@ -2724,7 +2724,7 @@ void PlotDigitalEx(const char* label_id, Getter getter, const ImPlotSpec& spec) int pixY_0 = (int)(s.Spec.LineWeight); itemData1.y = ImMax(0.0, itemData1.y); const float pixY_1 = s.Spec.Size * (float)itemData1.y; - const int pixY_chPosOffset = (int)(ImMax(s.Spec.Size, pixY_1) + s.Style.DigitalSpacing); + const int pixY_chPosOffset = (int)(ImMax(s.Spec.Size, pixY_1) + gp.Style.DigitalSpacing); pixYMax = ImMax(pixYMax, pixY_chPosOffset); ImVec2 pMin = PlotToPixels(itemData1,IMPLOT_AUTO,IMPLOT_AUTO); ImVec2 pMax = PlotToPixels(itemData2,IMPLOT_AUTO,IMPLOT_AUTO); From ff74c60a772924339e86247a84010d7171064281 Mon Sep 17 00:00:00 2001 From: Breno Cunha Queiroz Date: Wed, 11 Feb 2026 10:10:19 +0100 Subject: [PATCH 10/21] refactor: ImProp_X renamed to ImPlotProp_X --- implot.h | 78 ++++++++++++++++---------------- implot_demo.cpp | 118 ++++++++++++++++++++++++------------------------ 2 files changed, 98 insertions(+), 98 deletions(-) diff --git a/implot.h b/implot.h index 46dab0da..037b4f7a 100644 --- a/implot.h +++ b/implot.h @@ -83,7 +83,7 @@ struct ImPlotContext; // ImPlot context (opaque struct, see implot_i // Enums/Flags typedef int ImAxis; // -> enum ImAxis_ -typedef int ImProp; // -> enum ImProp_ +typedef int ImPlotProp; // -> enum ImPlotProp_ typedef int ImPlotFlags; // -> enum ImPlotFlags_ typedef int ImPlotAxisFlags; // -> enum ImPlotAxisFlags_ typedef int ImPlotSubplotFlags; // -> enum ImPlotSubplotFlags_ @@ -134,17 +134,17 @@ enum ImAxis_ { 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 +// Plotting properties. These provide syntactic sugar for creating ImPlotSpecs from (ImPlotProp,value) pairs. See ImPlotSpec documentation. +enum ImPlotProp_ { + ImPlotProp_LineColor, // line color (applies to lines, bar edges, marker edges); IMPLOT_AUTO_COL will use next Colormap color or current item color + ImPlotProp_LineWeight, // line weight in pixels (applies to lines, bar edges, marker edges) + ImPlotProp_FillColor, // fill color (applies to shaded regions, bar faces, marker faces); IMPLOT_AUTO_COL will use next Colormap color or current item color + ImPlotProp_FillAlpha, // alpha multiplier (applies to FillColor) + ImPlotProp_Marker, // marker type; specify ImPlotMarker_Auto to use the next unused marker + ImPlotProp_Size, // size of markers (radius), error bar whiskers (width or height), and digital bars (height) *in pixels* + ImPlotProp_Offset, // data index offset + ImPlotProp_Stride, // data stride in bytes; IMPLOT_AUTO will result in sizeof(T) where T is the type passed to PlotX + ImPlotProp_Flags // optional item flags; can be composed from common ImPlotItemFlags and/or specialized ImPlotXFlags }; // Options for plots (see BeginPlot). @@ -483,13 +483,13 @@ enum ImPlotBin_ { // spec.Flags = ImPlotItemFlags_NoLegend | ImPlotLineFlags_Segments; // ImPlot::PlotLine("MyLine", xs, ys, 100, spec); // -// 2. Inline using ImProp,value pairs (order does NOT matter): +// 2. Inline using (ImPlotProp,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 +// ImPlotProp_LineColor, ImVec4(1,0,0,1), +// ImPlotProp_LineWeight, 2.0f, +// ImPlotProp_Marker, ImPlotMarker_Circle, +// ImPlotProp_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 @@ -504,47 +504,47 @@ struct ImPlotSpec { ImPlotSpec() { } - // Construct a plot item specification from ImProp,value pairs in any order, e.g. ImPlotSpec(ImProp_LineColor, my_color, ImProp_Marker, 4.0f) + // Construct a plot item specification from (ImPlotProp,value) pairs in any order, e.g. ImPlotSpec(ImPlotProp_LineColor, my_color, ImPlotProp_Marker, 4.0f) template ImPlotSpec(Args... args) { - static_assert((sizeof ...(Args)) % 2 == 0, "Odd number of arguments! You must provide ImProp,value pairs!"); + static_assert((sizeof ...(Args)) % 2 == 0, "Odd number of arguments! You must provide (ImPlotProp,value) pairs!"); SetProp(args...); } - // Set properties from ImProp,value pairs in any order, e.g. SetProp(ImProp_LineColor, my_color, ImProp_Marker, 4.0f) + // Set properties from (ImPlotProp,value) pairs in any order, e.g. SetProp(ImPlotProp_LineColor, my_color, ImPlotProp_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!"); + void SetProp(ImPlotProp prop, Arg arg, Args... args) { + static_assert((sizeof ...(Args)) % 2 == 0, "Odd number of arguments! You must provide (ImPlotProp,value) pairs!"); SetProp(prop, arg); SetProp(args...); } // Set a property from a scalar value. template - void SetProp(ImProp prop, T v) { + void SetProp(ImPlotProp 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; + case ImPlotProp_LineColor : LineColor = ImGui::ColorConvertU32ToFloat4((ImU32)v); return; + case ImPlotProp_LineWeight : LineWeight = (float)v; return; + case ImPlotProp_FillColor : FillColor = ImGui::ColorConvertU32ToFloat4((ImU32)v); return; + case ImPlotProp_FillAlpha : FillAlpha = (float)v; return; + case ImPlotProp_Marker : Marker = (ImPlotMarker)v; return; + case ImPlotProp_Size : Size = (float)v; return; + case ImPlotProp_Offset : Offset = (int)v; return; + case ImPlotProp_Stride : Stride = (int)v; return; + case ImPlotProp_Flags : Flags = (ImPlotItemFlags)v; return; default: break; } - IM_ASSERT(0 && "User provided an ImProp which cannot be set from scalar value!"); - } + IM_ASSERT(0 && "User provided an ImPlotProp which cannot be set from scalar value!"); + } // Set a property from an ImVec4 value. - void SetProp(ImProp prop, const ImVec4& v) { + void SetProp(ImPlotProp prop, const ImVec4& v) { switch (prop) { - case ImProp_LineColor : LineColor = v; return; - case ImProp_FillColor : FillColor = v; return; + case ImPlotProp_LineColor : LineColor = v; return; + case ImPlotProp_FillColor : FillColor = v; return; default: break; } - IM_ASSERT(0 && "User provided an ImProp which cannot be set from ImVec4 value!"); + IM_ASSERT(0 && "User provided an ImPlotProp which cannot be set from ImVec4 value!"); } }; @@ -901,7 +901,7 @@ IMPLOT_API void SetNextAxesToFit(); // struct Vector2f { float X, Y; }; // ... // Vector2f data[42]; -// ImPlot::PlotLine("line", &data[0].x, &data[0].y, 42, {ImProp_Stride, sizeof(Vector2f}); +// ImPlot::PlotLine("line", &data[0].x, &data[0].y, 42, {ImPlotProp_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 diff --git a/implot_demo.cpp b/implot_demo.cpp index c13a7152..a10407ab 100644 --- a/implot_demo.cpp +++ b/implot_demo.cpp @@ -303,8 +303,8 @@ void Demo_LinePlots() { ImPlot::SetupAxes("x","y"); ImPlot::PlotLine("f(x)", xs1, ys1, 1001); ImPlot::PlotLine("g(x)", xs2, ys2, 20,{ - ImProp_Marker, ImPlotMarker_Circle, - ImProp_Flags, ImPlotLineFlags_Segments + ImPlotProp_Marker, ImPlotMarker_Circle, + ImPlotProp_Flags, ImPlotLineFlags_Segments }); ImPlot::EndPlot(); } @@ -378,7 +378,7 @@ void Demo_ShadedPlots() { ys3[i] = 0.75f + 0.2f * sinf(25 * xs[i]); ys4[i] = 0.75f + 0.1f * cosf(25 * xs[i]); } - static ImPlotSpec spec(ImProp_FillAlpha, 0.25f); + static ImPlotSpec spec(ImPlotProp_FillAlpha, 0.25f); ImGui::DragFloat("Alpha",&spec.FillAlpha,0.01f,0,1); if (ImPlot::BeginPlot("Shaded Plots")) { @@ -410,11 +410,11 @@ void Demo_ScatterPlots() { if (ImPlot::BeginPlot("Scatter Plot")) { ImPlot::PlotScatter("Data 1", xs1, ys1, 100); 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 + ImPlotProp_Marker, ImPlotMarker_Square, + ImPlotProp_Size, 6, + ImPlotProp_LineColor, GetColormapColor(1), + ImPlotProp_FillColor, GetColormapColor(1), + ImPlotProp_FillAlpha, 0.25f }); ImPlot::EndPlot(); } @@ -433,8 +433,8 @@ void Demo_StairstepPlots() { if (ImPlot::BeginPlot("Stairstep Plot")) { ImPlot::SetupAxes("x","f(x)"); ImPlot::SetupAxesLimits(0,1,0,1); - 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)}); + ImPlot::PlotLine("##1",ys1,21,0.05f, 0, {ImPlotProp_LineColor, ImVec4(0.5f,0.5f,0.5f,1.0f)}); + ImPlot::PlotLine("##2",ys2,21,0.05f, 0, {ImPlotProp_LineColor, ImVec4(0.5f,0.5f,0.5f,1.0f)}); ImPlotSpec spec; spec.Flags = flags; @@ -457,7 +457,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,{ImProp_Flags, ImPlotBarsFlags_Horizontal}); + ImPlot::PlotBars("Horizontal",data,10,0.4,1,{ImPlotProp_Flags, ImPlotBarsFlags_Horizontal}); ImPlot::EndPlot(); } } @@ -492,12 +492,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,{ImProp_Flags, flags|ImPlotBarGroupsFlags_Horizontal}); + ImPlot::PlotBarGroups(ilabels,data,items,groups,size,0,{ImPlotProp_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,{ImProp_Flags, flags}); + ImPlot::PlotBarGroups(ilabels,data,items,groups,size,0,{ImPlotProp_Flags, flags}); } ImPlot::EndPlot(); } @@ -571,8 +571,8 @@ void Demo_ErrorBars() { ImPlot::PlotBars("Bar", xs, bar, 5, 0.5f); ImPlot::PlotErrorBars("Bar", xs, bar, err1, 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}); + ImPlot::PlotErrorBars("Line", xs, lin1, err1, err2, 5, {ImPlotProp_LineColor, GetColormapColor(1), ImPlotProp_Size, 0}); + ImPlot::PlotLine("Line", xs, lin1, 5, {ImPlotProp_Marker, ImPlotMarker_Square}); ImPlotSpec spec; spec.LineColor = GetColormapColor(2); @@ -600,7 +600,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::PlotStems("Stems 2", xs, ys2,51, 0, {ImProp_Marker, ImPlotMarker_Circle}); + ImPlot::PlotStems("Stems 2", xs, ys2,51, 0, {ImPlotProp_Marker, ImPlotMarker_Circle}); ImPlot::EndPlot(); } } @@ -612,7 +612,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,{ImProp_Flags, ImPlotInfLinesFlags_Horizontal}); + ImPlot::PlotInfLines("Horizontal",vals,3,{ImPlotProp_Flags, ImPlotInfLinesFlags_Horizontal}); ImPlot::EndPlot(); } } @@ -632,7 +632,7 @@ void Demo_PieCharts() { if (ImPlot::BeginPlot("##Pie1", ImVec2(ImGui::GetTextLineHeight()*16,ImGui::GetTextLineHeight()*16), 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, {ImProp_Flags, flags}); + ImPlot::PlotPieChart(labels1, data1, 4, 0.5, 0.5, 0.4, "%.2f", 90, {ImPlotProp_Flags, flags}); ImPlot::EndPlot(); } @@ -645,7 +645,7 @@ void Demo_PieCharts() { if (ImPlot::BeginPlot("##Pie2", ImVec2(ImGui::GetTextLineHeight()*16,ImGui::GetTextLineHeight()*16), 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, {ImProp_Flags, flags}); + ImPlot::PlotPieChart(labels2, data2, 5, 0.5, 0.5, 0.4, "%.0f", 180, {ImPlotProp_Flags, flags}); ImPlot::EndPlot(); } ImPlot::PopColormap(); @@ -693,7 +693,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), {ImProp_Flags, hm_flags}); + ImPlot::PlotHeatmap("heat",values1[0],7,7,scale_min,scale_max,"%g",ImPlotPoint(0,0),ImPlotPoint(1,1), {ImPlotProp_Flags, hm_flags}); ImPlot::EndPlot(); } ImGui::SameLine(); @@ -772,8 +772,8 @@ void Demo_Histogram() { if (ImPlot::BeginPlot("##Histograms")) { ImPlot::SetupAxes(nullptr,nullptr,ImPlotAxisFlags_AutoFit,ImPlotAxisFlags_AutoFit); ImPlot::PlotHistogram("Empirical", dist.Data, 10000, bins, 1.0, range ? ImPlotRange(rmin,rmax) : ImPlotRange(), { - ImProp_FillAlpha, 0.5f, - ImProp_Flags, hist_flags + ImPlotProp_FillAlpha, 0.5f, + ImPlotProp_Flags, hist_flags }); if ((hist_flags & ImPlotHistogramFlags_Density) && !(hist_flags & ImPlotHistogramFlags_NoOutliers)) { if (hist_flags & ImPlotHistogramFlags_Horizontal) @@ -806,7 +806,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), {ImProp_Flags, hist_flags}); + max_count = ImPlot::PlotHistogram2D("Hist2D",dist1.Data,dist2.Data,count,xybins[0],xybins[1],ImPlotRect(-6,6,-6,6), {ImPlotProp_Flags, hist_flags}); ImPlot::EndPlot(); } ImGui::SameLine(); @@ -862,9 +862,9 @@ void Demo_DigitalPlots() { 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(), { - ImProp_Offset, dataDigital[i].Offset, - ImProp_Stride, 2 * sizeof(float), - ImProp_Size, (i+1) * 4 + ImPlotProp_Offset, dataDigital[i].Offset, + ImPlotProp_Stride, 2 * sizeof(float), + ImPlotProp_Size, (i+1) * 4 }); } } @@ -873,8 +873,8 @@ void Demo_DigitalPlots() { 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(), { - ImProp_Offset, dataAnalog[i].Offset, - ImProp_Stride, 2 * sizeof(float) + ImPlotProp_Offset, dataAnalog[i].Offset, + ImPlotProp_Stride, 2 * sizeof(float) }); } } @@ -968,7 +968,7 @@ void Demo_RealtimePlots() { //----------------------------------------------------------------------------- void Demo_MarkersAndText() { - static ImPlotSpec spec(ImProp_Marker, ImPlotMarker_Auto); + static ImPlotSpec spec(ImPlotProp_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"); @@ -1002,7 +1002,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), {ImProp_Flags, ImPlotTextFlags_Vertical}); + ImPlot::PlotText("Vertical Text", 5.0f, 6.0f, ImVec2(0,0), {ImPlotProp_Flags, ImPlotTextFlags_Vertical}); ImPlot::PopStyleColor(); ImPlot::EndPlot(); @@ -1028,8 +1028,8 @@ void Demo_NaNValues() { if (ImPlot::BeginPlot("##NaNValues")) { ImPlot::PlotLine("line", data1, data2, 5, { - ImProp_Flags, flags, - ImProp_Marker, ImPlotMarker_Square + ImPlotProp_Flags, flags, + ImPlotProp_Marker, ImPlotMarker_Square }); ImPlot::PlotBars("bars", data1, 5); ImPlot::EndPlot(); @@ -1112,7 +1112,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, {ImProp_Stride, sizeof(double)*downsample}); + ImPlot::PlotLine("Time Series", &data->Ts[start], &data->Ys[start], size, {ImPlotProp_Stride, sizeof(double)*downsample}); } // plot time now double t_now = (double)time(nullptr); @@ -1343,7 +1343,7 @@ void Demo_SubplotsSizing() { } char label[16]; snprintf(label, sizeof(label), "data%d", id++); - ImPlot::PlotLineG(label,SinewaveGetter,&fi,1000, {ImProp_LineColor, col}); + ImPlot::PlotLineG(label,SinewaveGetter,&fi,1000, {ImPlotProp_LineColor, col}); ImPlot::EndPlot(); } } @@ -1546,7 +1546,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::PlotLine("Interactive Data", xs, ys, 1000, {ImProp_LineWeight, hovered||held ? 2.0f : 1.0f}); + ImPlot::PlotLine("Interactive Data", xs, ys, 1000, {ImPlotProp_LineWeight, hovered||held ? 2.0f : 1.0f}); ImPlot::EndPlot(); } } @@ -1987,16 +1987,16 @@ void Demo_ItemStylingAndSpec() { 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): + // 2. Inline using ImPlotProp,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 + ImPlotProp_LineColor, ImVec4(0,1,1,1), + ImPlotProp_LineWeight, 1.0f, + ImPlotProp_FillColor, ImVec4(0,0,1,1), + ImPlotProp_FillAlpha, 0.5f, + ImPlotProp_Marker, ImPlotMarker_Diamond, + ImPlotProp_Size, 6, + ImPlotProp_Stride, sizeof(ImVec2), + ImPlotProp_Flags, ImPlotItemFlags_NoLegend | ImPlotLineFlags_Shaded }); ImPlot::EndPlot(); @@ -2030,7 +2030,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, {ImProp_Offset, offset, ImProp_Stride, 2 * k_circles*sizeof(double)}); + ImPlot::PlotLine(buff, &interleaved_data[c*2 + 0], &interleaved_data[c*2 + 1], k_points_per, {ImPlotProp_Offset, offset, ImPlotProp_Stride, 2 * k_circles*sizeof(double)}); } ImPlot::EndPlot(); ImPlot::PopColormap(); @@ -2053,7 +2053,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, {ImProp_Stride, sizeof(MyImPlot::Vector2f)}); + ImPlot::PlotLine("Vector2f", &vec2_data[0].x, &vec2_data[0].y, 2, {ImPlotProp_Stride, sizeof(MyImPlot::Vector2f)}); // custom getter example 1: ImPlot::PlotLineG("Spiral", MyImPlot::Spiral, nullptr, 1000); @@ -2063,7 +2063,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::PlotShadedG("Waves", MyImPlot::SineWave, &data1, MyImPlot::SawWave, &data2, 1000, {ImProp_FillAlpha, 0.25f}); + ImPlot::PlotShadedG("Waves", MyImPlot::SineWave, &data1, MyImPlot::SawWave, &data2, 1000, {ImPlotProp_FillAlpha, 0.25f}); // you can also pass C++ lambdas: // auto lambda = [](void* data, int idx) { ... return ImPlotPoint(x,y); }; @@ -2189,24 +2189,24 @@ void Demo_LegendPopups() { // rendering logic if (!line) { ImPlot::PlotBars("Right Click Me", vals, 101, 0.67, 0, { - ImProp_FillAlpha, alpha, - ImProp_FillColor, color + ImPlotProp_FillAlpha, alpha, + ImPlotProp_FillColor, color }); } else { ImPlot::PlotLine("Right Click Me", vals, 101, 1, 0, { - ImProp_LineColor, color, - ImProp_LineWeight, thickness + ImPlotProp_LineColor, color, + ImPlotProp_LineWeight, thickness }); if (markers) { ImPlot::PlotScatter("Right Click Me", vals, 101, 1, 0, { - ImProp_Marker, ImPlotMarker_Square, - ImProp_LineColor, color + ImPlotProp_Marker, ImPlotMarker_Square, + ImPlotProp_LineColor, color }); } if (shaded) { ImPlot::PlotShaded("Right Click Me",vals,101, 0, 1, 0, { - ImProp_FillAlpha, alpha, + ImPlotProp_FillAlpha, alpha, }); } } @@ -2462,11 +2462,11 @@ void Sparkline(const char* id, const float* values, int count, float min_v, floa ImPlot::SetupAxes(nullptr,nullptr,ImPlotAxisFlags_NoDecorations,ImPlotAxisFlags_NoDecorations); ImPlot::SetupAxesLimits(0, count - 1, min_v, max_v, ImGuiCond_Always); ImPlot::PlotLine(id, values, count, 1, 0, { - ImProp_LineColor, col, - ImProp_FillColor, col, - ImProp_FillAlpha, 0.25f, - ImProp_Offset, offset, - ImProp_Flags, ImPlotLineFlags_Shaded + ImPlotProp_LineColor, col, + ImPlotProp_FillColor, col, + ImPlotProp_FillAlpha, 0.25f, + ImPlotProp_Offset, offset, + ImPlotProp_Flags, ImPlotLineFlags_Shaded }); ImPlot::EndPlot(); } From 7da4b7a63bf50d652e0fc343b54574883f81dd20 Mon Sep 17 00:00:00 2001 From: Breno Cunha Queiroz Date: Wed, 11 Feb 2026 10:20:51 +0100 Subject: [PATCH 11/21] fix: linux workflow dependency installation --- .github/workflows/build.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 382ef8dd..d401e435 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -30,7 +30,9 @@ jobs: path: imgui - name: Dependencies - run: sudo apt-get install g++-multilib + run: | + sudo apt-get update + sudo apt-get install g++-multilib - name: Configure run: cmake -DCMAKE_CXX_COMPILER=${{ matrix.compiler }} -DCMAKE_C_COMPILER=${{ matrix.compiler }} -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} -DGCC_ARCH=${{ matrix.arch }} -B cmake-build -S .github From 4214151e67b19876b31daa718179770baf0d2adc Mon Sep 17 00:00:00 2001 From: Breno Cunha Queiroz Date: Wed, 11 Feb 2026 16:05:08 +0100 Subject: [PATCH 12/21] feat: add MarkerLineColor and MarkerFillColor to ImPlotProp --- implot.h | 66 ++++++++++++++++++++++++++--------------------- implot_demo.cpp | 4 +-- implot_internal.h | 2 ++ implot_items.cpp | 43 ++++++++++++++++-------------- 4 files changed, 65 insertions(+), 50 deletions(-) diff --git a/implot.h b/implot.h index 521749d7..0af19aab 100644 --- a/implot.h +++ b/implot.h @@ -136,15 +136,17 @@ enum ImAxis_ { // Plotting properties. These provide syntactic sugar for creating ImPlotSpecs from (ImPlotProp,value) pairs. See ImPlotSpec documentation. enum ImPlotProp_ { - ImPlotProp_LineColor, // line color (applies to lines, bar edges, marker edges); IMPLOT_AUTO_COL will use next Colormap color or current item color - ImPlotProp_LineWeight, // line weight in pixels (applies to lines, bar edges, marker edges) - ImPlotProp_FillColor, // fill color (applies to shaded regions, bar faces, marker faces); IMPLOT_AUTO_COL will use next Colormap color or current item color - ImPlotProp_FillAlpha, // alpha multiplier (applies to FillColor) - ImPlotProp_Marker, // marker type; specify ImPlotMarker_Auto to use the next unused marker - ImPlotProp_Size, // size of markers (radius), error bar whiskers (width or height), and digital bars (height) *in pixels* - ImPlotProp_Offset, // data index offset - ImPlotProp_Stride, // data stride in bytes; IMPLOT_AUTO will result in sizeof(T) where T is the type passed to PlotX - ImPlotProp_Flags // optional item flags; can be composed from common ImPlotItemFlags and/or specialized ImPlotXFlags + ImPlotProp_LineColor, // line color (applies to lines, bar edges); IMPLOT_AUTO_COL will use next Colormap color or current item color + ImPlotProp_LineWeight, // line weight in pixels (applies to lines, bar edges, marker edges) + ImPlotProp_FillColor, // fill color (applies to shaded regions, bar faces); IMPLOT_AUTO_COL will use next Colormap color or current item color + ImPlotProp_FillAlpha, // alpha multiplier (applies to FillColor and MarkerFillColor) + ImPlotProp_Marker, // marker type; specify ImPlotMarker_Auto to use the next unused marker + ImPlotProp_MarkerLineColor, // marker edge color; IMPLOT_AUTO_COL will use LineColor + ImPlotProp_MarkerFillColor, // marker face color; IMPLOT_AUTO_COL will use LineColor + ImPlotProp_Size, // size of markers (radius), error bar whiskers (width or height), and digital bars (height) *in pixels* + ImPlotProp_Offset, // data index offset + ImPlotProp_Stride, // data stride in bytes; IMPLOT_AUTO will result in sizeof(T) where T is the type passed to PlotX + ImPlotProp_Flags // optional item flags; can be composed from common ImPlotItemFlags and/or specialized ImPlotXFlags }; // Options for plots (see BeginPlot). @@ -492,15 +494,17 @@ enum ImPlotBin_ { // ImPlotProp_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 + ImVec4 LineColor = IMPLOT_AUTO_COL; // line color (applies to lines, bar 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); IMPLOT_AUTO_COL will use next Colormap color or current item color + float FillAlpha = 1.0f; // alpha multiplier (applies to FillColor and MarkerFillColor) + ImPlotMarker Marker = ImPlotMarker_None; // marker type; specify ImPlotMarker_Auto to use the next unused marker + ImVec4 MarkerLineColor = IMPLOT_AUTO_COL; // marker edge color; IMPLOT_AUTO_COL will use LineColor + ImVec4 MarkerFillColor = IMPLOT_AUTO_COL; // marker face color; IMPLOT_AUTO_COL will use LineColor + 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() { } @@ -523,15 +527,17 @@ struct ImPlotSpec { template void SetProp(ImPlotProp prop, T v) { switch (prop) { - case ImPlotProp_LineColor : LineColor = ImGui::ColorConvertU32ToFloat4((ImU32)v); return; - case ImPlotProp_LineWeight : LineWeight = (float)v; return; - case ImPlotProp_FillColor : FillColor = ImGui::ColorConvertU32ToFloat4((ImU32)v); return; - case ImPlotProp_FillAlpha : FillAlpha = (float)v; return; - case ImPlotProp_Marker : Marker = (ImPlotMarker)v; return; - case ImPlotProp_Size : Size = (float)v; return; - case ImPlotProp_Offset : Offset = (int)v; return; - case ImPlotProp_Stride : Stride = (int)v; return; - case ImPlotProp_Flags : Flags = (ImPlotItemFlags)v; return; + case ImPlotProp_LineColor : LineColor = ImGui::ColorConvertU32ToFloat4((ImU32)v); return; + case ImPlotProp_LineWeight : LineWeight = (float)v; return; + case ImPlotProp_FillColor : FillColor = ImGui::ColorConvertU32ToFloat4((ImU32)v); return; + case ImPlotProp_FillAlpha : FillAlpha = (float)v; return; + case ImPlotProp_Marker : Marker = (ImPlotMarker)v; return; + case ImPlotProp_MarkerLineColor : MarkerLineColor = ImGui::ColorConvertU32ToFloat4((ImU32)v); return; + case ImPlotProp_MarkerFillColor : MarkerFillColor = ImGui::ColorConvertU32ToFloat4((ImU32)v); return; + case ImPlotProp_Size : Size = (float)v; return; + case ImPlotProp_Offset : Offset = (int)v; return; + case ImPlotProp_Stride : Stride = (int)v; return; + case ImPlotProp_Flags : Flags = (ImPlotItemFlags)v; return; default: break; } IM_ASSERT(0 && "User provided an ImPlotProp which cannot be set from scalar value!"); @@ -540,8 +546,10 @@ struct ImPlotSpec { // Set a property from an ImVec4 value. void SetProp(ImPlotProp prop, const ImVec4& v) { switch (prop) { - case ImPlotProp_LineColor : LineColor = v; return; - case ImPlotProp_FillColor : FillColor = v; return; + case ImPlotProp_LineColor : LineColor = v; return; + case ImPlotProp_FillColor : FillColor = v; return; + case ImPlotProp_MarkerLineColor : MarkerLineColor = v; return; + case ImPlotProp_MarkerFillColor : MarkerFillColor = v; return; default: break; } IM_ASSERT(0 && "User provided an ImPlotProp which cannot be set from ImVec4 value!"); diff --git a/implot_demo.cpp b/implot_demo.cpp index 5246ba1b..631e1edd 100644 --- a/implot_demo.cpp +++ b/implot_demo.cpp @@ -439,9 +439,9 @@ void Demo_StairstepPlots() { ImPlotSpec spec; spec.Flags = flags; spec.FillAlpha = 0.25f; - spec.Marker = ImPlotMarker_Auto; + 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; diff --git a/implot_internal.h b/implot_internal.h index 684c0aa4..90d61dd2 100644 --- a/implot_internal.h +++ b/implot_internal.h @@ -1216,6 +1216,8 @@ struct ImPlotNextItemData { ImPlotSpec Spec; bool RenderLine; bool RenderFill; + bool RenderMarkerLine; + bool RenderMarkerFill; bool RenderMarkers; bool HasHidden; bool Hidden; diff --git a/implot_items.cpp b/implot_items.cpp index 1fb71f49..e74dbb41 100644 --- a/implot_items.cpp +++ b/implot_items.cpp @@ -119,12 +119,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; + 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); @@ -419,12 +419,15 @@ bool BeginItem(const char* label_id, const ImPlotSpec& spec, const ImVec4& item_ 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; + s.Spec.MarkerLineColor = IsColorAuto(s.Spec.MarkerLineColor) ? s.Spec.LineColor : s.Spec.MarkerLineColor; + s.Spec.MarkerFillColor = IsColorAuto(s.Spec.MarkerFillColor) ? s.Spec.LineColor : s.Spec.MarkerFillColor; + s.Spec.MarkerFillColor.w *= s.Spec.FillAlpha; // apply highlight mods if (item->LegendHovered) { if (!ImHasFlag(gp.CurrentItems->Legend.Flags, ImPlotLegendFlags_NoHighlightItem)) { s.Spec.LineWeight *= ITEM_HIGHLIGHT_LINE_SCALE; s.Spec.Size *= ITEM_HIGHLIGHT_MARK_SCALE; - // TODO: how to highlight fills? + // TODO: how to highlight fills? } if (!ImHasFlag(gp.CurrentItems->Legend.Flags, ImPlotLegendFlags_NoHighlightAxis)) { if (gp.CurrentPlot->EnabledAxesX() > 1) @@ -436,7 +439,9 @@ bool BeginItem(const char* label_id, const ImPlotSpec& spec, const ImVec4& item_ // set render flags 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); + s.RenderMarkerLine = s.Spec.MarkerLineColor.w > 0 && s.Spec.LineWeight > 0; + s.RenderMarkerFill = s.Spec.MarkerFillColor.w > 0; + s.RenderMarkers = s.Spec.Marker >= 0 && (s.RenderMarkerFill || s.RenderMarkerLine); // push rendering clip rect PushPlotClipRect(); return true; @@ -1481,7 +1486,7 @@ constexpr ImVec2 MARKER_FILL_UP[3] = {ImVec2(SQRT_3_2,0.5f),ImVec2(0,-1),I 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), @@ -1586,9 +1591,9 @@ void PlotLineEx(const char* label_id, const _Getter& getter, const ImPlotSpec& s PopPlotClipRect(); PushPlotClipRect(s.Spec.Size); } - 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); + const ImU32 col_line = ImGui::GetColorU32(s.Spec.MarkerLineColor); + const ImU32 col_fill = ImGui::GetColorU32(s.Spec.MarkerFillColor); + RenderMarkers<_Getter>(getter, s.Spec.Marker, s.Spec.Size, s.RenderMarkerFill, col_fill, s.RenderMarkerLine, col_line, s.Spec.LineWeight); } EndItem(); } @@ -1637,9 +1642,9 @@ void PlotScatterEx(const char* label_id, const Getter& getter, const ImPlotSpec& PopPlotClipRect(); 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); + const ImU32 col_line = ImGui::GetColorU32(s.Spec.MarkerLineColor); + const ImU32 col_fill = ImGui::GetColorU32(s.Spec.MarkerFillColor); + RenderMarkers(getter, s.Spec.Marker, s.Spec.Size, s.RenderMarkerFill, col_fill, s.RenderMarkerLine, col_line, s.Spec.LineWeight); } EndItem(); } @@ -1701,9 +1706,9 @@ void PlotStairsEx(const char* label_id, const Getter& getter, const ImPlotSpec& if (s.RenderMarkers) { PopPlotClipRect(); 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); + const ImU32 col_line = ImGui::GetColorU32(s.Spec.MarkerLineColor); + const ImU32 col_fill = ImGui::GetColorU32(s.Spec.MarkerFillColor); + RenderMarkers(getter, s.Spec.Marker, s.Spec.Size, s.RenderMarkerFill, col_fill, s.RenderMarkerLine, col_line, s.Spec.LineWeight); } EndItem(); } @@ -1902,7 +1907,7 @@ 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, const ImPlotSpec& spec) { - IndexerIdx indexer(values,item_count*group_count,spec.Offset,Stride(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; @@ -2094,9 +2099,9 @@ void PlotStemsEx(const char* label_id, const _GetterM& getter_mark, const _Gette if (s.RenderMarkers) { PopPlotClipRect(); 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); + const ImU32 col_line = ImGui::GetColorU32(s.Spec.MarkerLineColor); + const ImU32 col_fill = ImGui::GetColorU32(s.Spec.MarkerFillColor); + RenderMarkers<_GetterM>(getter_mark, s.Spec.Marker, s.Spec.Size, s.RenderMarkerFill, col_fill, s.RenderMarkerLine, col_line, s.Spec.LineWeight); } EndItem(); } From 6ae00c5c4945ea5d5de4e4c6c7b228c27a5b9ef6 Mon Sep 17 00:00:00 2001 From: Breno Cunha Queiroz Date: Wed, 11 Feb 2026 17:00:21 +0100 Subject: [PATCH 13/21] refactor: revert template machinery to use raw pointers instead --- implot_internal.h | 34 ++++++++++++++-------------------- implot_items.cpp | 40 ++++++++++++++++++++++++++++++++++++---- 2 files changed, 50 insertions(+), 24 deletions(-) diff --git a/implot_internal.h b/implot_internal.h index 90d61dd2..2e9d3f94 100644 --- a/implot_internal.h +++ b/implot_internal.h @@ -138,22 +138,16 @@ static inline double ImConstrainTime(double val) { return val < IMPLOT_MIN_TIME // 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 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; } +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; } // Finds the max value in an unsorted array -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; } +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; } // Finds the min and max value in an unsorted array -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]; +template +static inline void ImMinMaxArray(const T* values, int count, T* min_out, T* max_out) { + T Min = values[0]; 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]; } @@ -161,16 +155,16 @@ static inline void ImMinMaxArray(const TContainer& values, int count, value_type *min_out = Min; *max_out = Max; } // Finds the sim of an array -template -static inline value_type_t ImSum(const TContainer& values, int count) { - value_type_t sum = 0; +template +static inline T ImSum(const T* values, int count) { + 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 TContainer& values, int count) { +template +static inline double ImMean(const T* values, int count) { double den = 1.0 / count; double mu = 0; for (int i = 0; i < count; ++i) @@ -178,8 +172,8 @@ static inline double ImMean(const TContainer& values, int count) { return mu; } // Finds the sample standard deviation of an array -template -static inline double ImStdDev(const TContainer& values, int count) { +template +static inline double ImStdDev(const T* values, int count) { double den = 1.0 / (count - 1.0); double mu = ImMean(values, count); double x = 0; diff --git a/implot_items.cpp b/implot_items.cpp index e74dbb41..26ce6bc8 100644 --- a/implot_items.cpp +++ b/implot_items.cpp @@ -125,6 +125,38 @@ int Stride(const ImPlotSpec& spec) { return spec.Stride == IMPLOT_AUTO ? sizeof(T) : spec.Stride; } +// Finds the min and max value in an unsorted array +template +static inline void ImMinMaxIndexer(const Indexer& values, int count, T* min_out, T* max_out) { + T Min = values[0]; 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]; } + } + *min_out = Min; *max_out = Max; +} + +// Finds the mean of a container +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) + mu += (double)values[i] * den; + return mu; +} + +// Finds the sample standard deviation of a container +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; + for (int i = 0; i < count; ++i) + x += ((double)values[i] - mu) * ((double)values[i] - mu) * den; + return sqrt(x); +} + 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); @@ -2445,7 +2477,7 @@ void RenderHeatmap(ImDrawList& draw_list, IndexerIdx indexer, int rows, int c ImPlotContext& gp = *GImPlot; Transformer2 transformer; if (scale_min == 0 && scale_max == 0) { - ImMinMaxArray(indexer,rows*cols,&scale_min,&scale_max); + ImMinMaxIndexer(indexer,rows*cols,&scale_min,&scale_max); } if (scale_min == scale_max) { ImVec2 a = transformer(bounds_min); @@ -2544,7 +2576,7 @@ double PlotHistogram(const char* label_id, const T* values, int count, int bins, return 0; if (range.Min == 0 && range.Max == 0) { - ImMinMaxArray(indexer, count, &range.Min, &range.Max); + ImMinMaxIndexer(indexer, count, &range.Min, &range.Max); } double width; @@ -2636,10 +2668,10 @@ double PlotHistogram2D(const char* label_id, const T* xs, const T* ys, int count return 0; if (range.X.Min == 0 && range.X.Max == 0) { - ImMinMaxArray(indexer_x, count, &range.X.Min, &range.X.Min); + ImMinMaxIndexer(indexer_x, count, &range.X.Min, &range.X.Min); } if (range.Y.Min == 0 && range.Y.Max == 0) { - ImMinMaxArray(indexer_y, count, &range.Y.Min, &range.Y.Max); + ImMinMaxIndexer(indexer_y, count, &range.Y.Min, &range.Y.Max); } double width, height; From 23c1a79e856dc11e86ed282103b97f8623ec378f Mon Sep 17 00:00:00 2001 From: Breno Cunha Queiroz Date: Wed, 11 Feb 2026 17:40:54 +0100 Subject: [PATCH 14/21] feat: populate ImPlotSpec using (string, value) pair --- implot.h | 66 +++++++++++++++++++++++++++++++++++++++++-------- implot_demo.cpp | 20 +++++++-------- 2 files changed, 66 insertions(+), 20 deletions(-) diff --git a/implot.h b/implot.h index 0af19aab..89090ce1 100644 --- a/implot.h +++ b/implot.h @@ -493,6 +493,15 @@ enum ImPlotBin_ { // ImPlotProp_Marker, ImPlotMarker_Circle, // ImPlotProp_Flags, ImPlotItemFlags_NoLegend | ImPlotLineFlags_Segments // }); +// +// 3. Inline using (String,value) pairs (order does NOT matter): +// +// ImPlot::PlotLine("MyLine", xs, ys, 100, { +// "LineColor", ImVec4(1,0,0,1), +// "LineWeight", 2.0f, +// "Marker", ImPlotMarker_Circle, +// "Flags", ImPlotItemFlags_NoLegend | ImPlotLineFlags_Segments +// }); struct ImPlotSpec { ImVec4 LineColor = IMPLOT_AUTO_COL; // line color (applies to lines, bar 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) @@ -511,16 +520,8 @@ struct ImPlotSpec { // Construct a plot item specification from (ImPlotProp,value) pairs in any order, e.g. ImPlotSpec(ImPlotProp_LineColor, my_color, ImPlotProp_Marker, 4.0f) template ImPlotSpec(Args... args) { - static_assert((sizeof ...(Args)) % 2 == 0, "Odd number of arguments! You must provide (ImPlotProp,value) pairs!"); - SetProp(args...); - } - - // Set properties from (ImPlotProp,value) pairs in any order, e.g. SetProp(ImPlotProp_LineColor, my_color, ImPlotProp_Marker, 4.0f) - template - void SetProp(ImPlotProp prop, Arg arg, Args... args) { - static_assert((sizeof ...(Args)) % 2 == 0, "Odd number of arguments! You must provide (ImPlotProp,value) pairs!"); - SetProp(prop, arg); - SetProp(args...); + static_assert((sizeof ...(Args)) % 2 == 0, "Odd number of arguments! You must provide (property, value) pairs!"); + Apply(args...); } // Set a property from a scalar value. @@ -554,6 +555,51 @@ struct ImPlotSpec { } IM_ASSERT(0 && "User provided an ImPlotProp which cannot be set from ImVec4 value!"); } + + // Helper to convert string to enum + static inline ImPlotProp StringToProp(const char* name) { + if (strcmp(name, "LineColor") == 0) return ImPlotProp_LineColor; + if (strcmp(name, "LineWeight") == 0) return ImPlotProp_LineWeight; + if (strcmp(name, "FillColor") == 0) return ImPlotProp_FillColor; + if (strcmp(name, "FillAlpha") == 0) return ImPlotProp_FillAlpha; + if (strcmp(name, "Marker") == 0) return ImPlotProp_Marker; + if (strcmp(name, "MarkerLineColor") == 0) return ImPlotProp_MarkerLineColor; + if (strcmp(name, "MarkerFillColor") == 0) return ImPlotProp_MarkerFillColor; + if (strcmp(name, "Size") == 0) return ImPlotProp_Size; + if (strcmp(name, "Offset") == 0) return ImPlotProp_Offset; + if (strcmp(name, "Stride") == 0) return ImPlotProp_Stride; + if (strcmp(name, "Flags") == 0) return ImPlotProp_Flags; + return (ImPlotProp)-1; + } + + // Set property from string and scalar + template + void SetProp(const char* prop_name, T v) { + ImPlotProp prop = StringToProp(prop_name); + if (prop != -1) + SetProp(prop, v); + else + IM_ASSERT(0 && "Invalid ImPlotProp string name!"); + } + + // Set property from string and ImVec4 + void SetProp(const char* prop_name, const ImVec4& v) { + ImPlotProp prop = StringToProp(prop_name); + if (prop != -1) + SetProp(prop, v); + else + IM_ASSERT(0 && "Invalid ImPlotProp string name!"); + } + + // Base case + void Apply() { } + + // Set properties from (ImPlotProp,value) pairs in any order, e.g. SetProp(ImPlotProp_LineColor, my_color, ImPlotProp_Marker, 4.0f) + template + void Apply(Key key, Value val, Args... args) { + SetProp(key, val); + Apply(args...); + } }; // Double precision version of ImVec2 used by ImPlot. Extensible by end users. diff --git a/implot_demo.cpp b/implot_demo.cpp index 631e1edd..2da7210f 100644 --- a/implot_demo.cpp +++ b/implot_demo.cpp @@ -410,11 +410,11 @@ void Demo_ScatterPlots() { if (ImPlot::BeginPlot("Scatter Plot")) { ImPlot::PlotScatter("Data 1", xs1, ys1, 100); ImPlot::PlotScatter("Data 2", xs2, ys2, 50, { - ImPlotProp_Marker, ImPlotMarker_Square, - ImPlotProp_Size, 6, - ImPlotProp_LineColor, GetColormapColor(1), - ImPlotProp_FillColor, GetColormapColor(1), - ImPlotProp_FillAlpha, 0.25f + "Marker", ImPlotMarker_Square, + "Size", 6, + "LineColor", GetColormapColor(1), + "FillColor", GetColormapColor(1), + "FillAlpha", 0.25f }); ImPlot::EndPlot(); } @@ -567,10 +567,10 @@ 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::PlotErrorBars("Line", xs, lin1, err1, err2, 5, {ImPlotProp_LineColor, GetColormapColor(1), ImPlotProp_Size, 0}); ImPlot::PlotLine("Line", xs, lin1, 5, {ImPlotProp_Marker, ImPlotMarker_Square}); @@ -581,8 +581,8 @@ void Demo_ErrorBars() { 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::PlotScatter("Scatter", xs, lin2, 5); + ImPlot::EndPlot(); } } @@ -600,7 +600,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::PlotStems("Stems 2", xs, ys2,51, 0, {ImPlotProp_Marker, ImPlotMarker_Circle}); + ImPlot::PlotStems("Stems 2", xs, ys2,51, 0, {"Marker", ImPlotMarker_Circle}); ImPlot::EndPlot(); } } From dffceafc6e35de811ae23d8a5507666d8f720208 Mon Sep 17 00:00:00 2001 From: Breno Cunha Queiroz Date: Wed, 11 Feb 2026 18:18:09 +0100 Subject: [PATCH 15/21] feat: separate MarkerSize from error whisker/digital bar Size --- implot.h | 8 ++++++-- implot_demo.cpp | 18 +++++++++--------- implot_items.cpp | 17 +++++++++-------- 3 files changed, 24 insertions(+), 19 deletions(-) diff --git a/implot.h b/implot.h index 89090ce1..530cb049 100644 --- a/implot.h +++ b/implot.h @@ -141,9 +141,10 @@ enum ImPlotProp_ { ImPlotProp_FillColor, // fill color (applies to shaded regions, bar faces); IMPLOT_AUTO_COL will use next Colormap color or current item color ImPlotProp_FillAlpha, // alpha multiplier (applies to FillColor and MarkerFillColor) ImPlotProp_Marker, // marker type; specify ImPlotMarker_Auto to use the next unused marker + ImPlotProp_MarkerSize, // size of markers (radius) *in pixels* ImPlotProp_MarkerLineColor, // marker edge color; IMPLOT_AUTO_COL will use LineColor ImPlotProp_MarkerFillColor, // marker face color; IMPLOT_AUTO_COL will use LineColor - ImPlotProp_Size, // size of markers (radius), error bar whiskers (width or height), and digital bars (height) *in pixels* + ImPlotProp_Size, // size of error bar whiskers (width or height), and digital bars (height) *in pixels* ImPlotProp_Offset, // data index offset ImPlotProp_Stride, // data stride in bytes; IMPLOT_AUTO will result in sizeof(T) where T is the type passed to PlotX ImPlotProp_Flags // optional item flags; can be composed from common ImPlotItemFlags and/or specialized ImPlotXFlags @@ -508,9 +509,10 @@ struct ImPlotSpec { ImVec4 FillColor = IMPLOT_AUTO_COL; // fill color (applies to shaded regions, bar faces); IMPLOT_AUTO_COL will use next Colormap color or current item color float FillAlpha = 1.0f; // alpha multiplier (applies to FillColor and MarkerFillColor) ImPlotMarker Marker = ImPlotMarker_None; // marker type; specify ImPlotMarker_Auto to use the next unused marker + float MarkerSize = 4; // size of markers (radius) *in pixels* ImVec4 MarkerLineColor = IMPLOT_AUTO_COL; // marker edge color; IMPLOT_AUTO_COL will use LineColor ImVec4 MarkerFillColor = IMPLOT_AUTO_COL; // marker face color; IMPLOT_AUTO_COL will use LineColor - float Size = 4; // size of markers (radius), error bar whiskers (width or height), and digital bars (height) *in pixels* + float Size = 4; // size of 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 @@ -533,6 +535,7 @@ struct ImPlotSpec { case ImPlotProp_FillColor : FillColor = ImGui::ColorConvertU32ToFloat4((ImU32)v); return; case ImPlotProp_FillAlpha : FillAlpha = (float)v; return; case ImPlotProp_Marker : Marker = (ImPlotMarker)v; return; + case ImPlotProp_MarkerSize : MarkerSize = (float)v; return; case ImPlotProp_MarkerLineColor : MarkerLineColor = ImGui::ColorConvertU32ToFloat4((ImU32)v); return; case ImPlotProp_MarkerFillColor : MarkerFillColor = ImGui::ColorConvertU32ToFloat4((ImU32)v); return; case ImPlotProp_Size : Size = (float)v; return; @@ -563,6 +566,7 @@ struct ImPlotSpec { if (strcmp(name, "FillColor") == 0) return ImPlotProp_FillColor; if (strcmp(name, "FillAlpha") == 0) return ImPlotProp_FillAlpha; if (strcmp(name, "Marker") == 0) return ImPlotProp_Marker; + if (strcmp(name, "MarkerSize") == 0) return ImPlotProp_MarkerSize; if (strcmp(name, "MarkerLineColor") == 0) return ImPlotProp_MarkerLineColor; if (strcmp(name, "MarkerFillColor") == 0) return ImPlotProp_MarkerFillColor; if (strcmp(name, "Size") == 0) return ImPlotProp_Size; diff --git a/implot_demo.cpp b/implot_demo.cpp index 2da7210f..d5471b0c 100644 --- a/implot_demo.cpp +++ b/implot_demo.cpp @@ -411,7 +411,7 @@ void Demo_ScatterPlots() { ImPlot::PlotScatter("Data 1", xs1, ys1, 100); ImPlot::PlotScatter("Data 2", xs2, ys2, 50, { "Marker", ImPlotMarker_Square, - "Size", 6, + "MarkerSize", 6, "LineColor", GetColormapColor(1), "FillColor", GetColormapColor(1), "FillAlpha", 0.25f @@ -580,7 +580,7 @@ void Demo_ErrorBars() { 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::PlotErrorBars("Scatter", xs, lin2, err3, err4, 5, spec); ImPlot::PlotScatter("Scatter", xs, lin2, 5); ImPlot::EndPlot(); @@ -969,7 +969,7 @@ void Demo_RealtimePlots() { void Demo_MarkersAndText() { static ImPlotSpec spec(ImPlotProp_Marker, ImPlotMarker_Auto); - ImGui::DragFloat("Marker Size",&spec.Size,0.1f,2.0f,10.0f,"%.2f px"); + ImGui::DragFloat("Marker Size",&spec.MarkerSize,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)) { @@ -1661,7 +1661,7 @@ void Demo_Querying() { spec.Stride = 2 * sizeof(double); ImPlotSpec cent_spec; cent_spec.Marker = ImPlotMarker_Square; - cent_spec.Size = 6; + cent_spec.MarkerSize = 6; ImPlot::PlotScatter("Points", &data[0].x, &data[0].y, data.size(), spec); if (ImPlot::IsPlotSelected()) { select = ImPlot::GetPlotSelection(); @@ -1982,11 +1982,11 @@ void Demo_ItemStylingAndSpec() { spec.FillColor = ImVec4(1,0.5f,0,1); spec.FillAlpha = 0.5f; spec.Marker = ImPlotMarker_Square; - spec.Size = 6; + spec.MarkerSize = 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 ImPlotProp,value pairs (order does NOT matter): ImPlot::PlotLine("Line 2", &data2[0].x, &data2[0].y, 20, { ImPlotProp_LineColor, ImVec4(0,1,1,1), @@ -1998,11 +1998,11 @@ void Demo_ItemStylingAndSpec() { ImPlotProp_Stride, sizeof(ImVec2), ImPlotProp_Flags, ImPlotItemFlags_NoLegend | ImPlotLineFlags_Shaded }); - + ImPlot::EndPlot(); - } + } } - + //----------------------------------------------------------------------------- void Demo_OffsetAndStride() { diff --git a/implot_items.cpp b/implot_items.cpp index 26ce6bc8..a8c51964 100644 --- a/implot_items.cpp +++ b/implot_items.cpp @@ -458,6 +458,7 @@ bool BeginItem(const char* label_id, const ImPlotSpec& spec, const ImVec4& item_ if (item->LegendHovered) { if (!ImHasFlag(gp.CurrentItems->Legend.Flags, ImPlotLegendFlags_NoHighlightItem)) { s.Spec.LineWeight *= ITEM_HIGHLIGHT_LINE_SCALE; + s.Spec.MarkerSize *= ITEM_HIGHLIGHT_MARK_SCALE; s.Spec.Size *= ITEM_HIGHLIGHT_MARK_SCALE; // TODO: how to highlight fills? } @@ -1621,11 +1622,11 @@ void PlotLineEx(const char* label_id, const _Getter& getter, const ImPlotSpec& s if (s.RenderMarkers) { if (ImHasFlag(spec.Flags, ImPlotLineFlags_NoClip)) { PopPlotClipRect(); - PushPlotClipRect(s.Spec.Size); + PushPlotClipRect(s.Spec.MarkerSize); } const ImU32 col_line = ImGui::GetColorU32(s.Spec.MarkerLineColor); const ImU32 col_fill = ImGui::GetColorU32(s.Spec.MarkerFillColor); - RenderMarkers<_Getter>(getter, s.Spec.Marker, s.Spec.Size, s.RenderMarkerFill, col_fill, s.RenderMarkerLine, col_line, s.Spec.LineWeight); + RenderMarkers<_Getter>(getter, s.Spec.Marker, s.Spec.MarkerSize, s.RenderMarkerFill, col_fill, s.RenderMarkerLine, col_line, s.Spec.LineWeight); } EndItem(); } @@ -1672,11 +1673,11 @@ void PlotScatterEx(const char* label_id, const Getter& getter, const ImPlotSpec& if (s.RenderMarkers) { if (ImHasFlag(spec.Flags,ImPlotScatterFlags_NoClip)) { PopPlotClipRect(); - PushPlotClipRect(s.Spec.Size); + PushPlotClipRect(s.Spec.MarkerSize); } const ImU32 col_line = ImGui::GetColorU32(s.Spec.MarkerLineColor); const ImU32 col_fill = ImGui::GetColorU32(s.Spec.MarkerFillColor); - RenderMarkers(getter, s.Spec.Marker, s.Spec.Size, s.RenderMarkerFill, col_fill, s.RenderMarkerLine, col_line, s.Spec.LineWeight); + RenderMarkers(getter, s.Spec.Marker, s.Spec.MarkerSize, s.RenderMarkerFill, col_fill, s.RenderMarkerLine, col_line, s.Spec.LineWeight); } EndItem(); } @@ -1737,10 +1738,10 @@ void PlotStairsEx(const char* label_id, const Getter& getter, const ImPlotSpec& // render markers if (s.RenderMarkers) { PopPlotClipRect(); - PushPlotClipRect(s.Spec.Size); + PushPlotClipRect(s.Spec.MarkerSize); const ImU32 col_line = ImGui::GetColorU32(s.Spec.MarkerLineColor); const ImU32 col_fill = ImGui::GetColorU32(s.Spec.MarkerFillColor); - RenderMarkers(getter, s.Spec.Marker, s.Spec.Size, s.RenderMarkerFill, col_fill, s.RenderMarkerLine, col_line, s.Spec.LineWeight); + RenderMarkers(getter, s.Spec.Marker, s.Spec.MarkerSize, s.RenderMarkerFill, col_fill, s.RenderMarkerLine, col_line, s.Spec.LineWeight); } EndItem(); } @@ -2130,10 +2131,10 @@ void PlotStemsEx(const char* label_id, const _GetterM& getter_mark, const _Gette // render markers if (s.RenderMarkers) { PopPlotClipRect(); - PushPlotClipRect(s.Spec.Size); + PushPlotClipRect(s.Spec.MarkerSize); const ImU32 col_line = ImGui::GetColorU32(s.Spec.MarkerLineColor); const ImU32 col_fill = ImGui::GetColorU32(s.Spec.MarkerFillColor); - RenderMarkers<_GetterM>(getter_mark, s.Spec.Marker, s.Spec.Size, s.RenderMarkerFill, col_fill, s.RenderMarkerLine, col_line, s.Spec.LineWeight); + RenderMarkers<_GetterM>(getter_mark, s.Spec.Marker, s.Spec.MarkerSize, s.RenderMarkerFill, col_fill, s.RenderMarkerLine, col_line, s.Spec.LineWeight); } EndItem(); } From 8ef1a31362c4d459877e563dae2e29de2605eea6 Mon Sep 17 00:00:00 2001 From: Breno Cunha Queiroz Date: Thu, 12 Feb 2026 06:53:26 +0100 Subject: [PATCH 16/21] refactor: remove imgui_internal include --- implot.h | 1 - 1 file changed, 1 deletion(-) diff --git a/implot.h b/implot.h index 530cb049..7a00d528 100644 --- a/implot.h +++ b/implot.h @@ -47,7 +47,6 @@ #pragma once #include "imgui.h" -#include "imgui_internal.h" #ifndef IMGUI_DISABLE //----------------------------------------------------------------------------- From 0570fdff26965ddf71aa29e8bb34d93113e5c060 Mon Sep 17 00:00:00 2001 From: Breno Cunha Queiroz Date: Thu, 12 Feb 2026 07:04:35 +0100 Subject: [PATCH 17/21] refactor: revert inline string,value pairs --- implot.h | 67 ++++++++----------------------------------------- implot_demo.cpp | 12 ++++----- 2 files changed, 16 insertions(+), 63 deletions(-) diff --git a/implot.h b/implot.h index 7a00d528..2d6760fe 100644 --- a/implot.h +++ b/implot.h @@ -493,15 +493,6 @@ enum ImPlotBin_ { // ImPlotProp_Marker, ImPlotMarker_Circle, // ImPlotProp_Flags, ImPlotItemFlags_NoLegend | ImPlotLineFlags_Segments // }); -// -// 3. Inline using (String,value) pairs (order does NOT matter): -// -// ImPlot::PlotLine("MyLine", xs, ys, 100, { -// "LineColor", ImVec4(1,0,0,1), -// "LineWeight", 2.0f, -// "Marker", ImPlotMarker_Circle, -// "Flags", ImPlotItemFlags_NoLegend | ImPlotLineFlags_Segments -// }); struct ImPlotSpec { ImVec4 LineColor = IMPLOT_AUTO_COL; // line color (applies to lines, bar 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) @@ -521,8 +512,16 @@ struct ImPlotSpec { // Construct a plot item specification from (ImPlotProp,value) pairs in any order, e.g. ImPlotSpec(ImPlotProp_LineColor, my_color, ImPlotProp_Marker, 4.0f) template ImPlotSpec(Args... args) { - static_assert((sizeof ...(Args)) % 2 == 0, "Odd number of arguments! You must provide (property, value) pairs!"); - Apply(args...); + static_assert((sizeof ...(Args)) % 2 == 0, "Odd number of arguments! You must provide (ImPlotProp, value) pairs!"); + SetProp(args...); + } + + // Set properties from (ImPlotProp,value) pairs in any order, e.g. SetProp(ImPlotProp_LineColor, my_color, ImPlotProp_Marker, 4.0f) + template + void SetProp(ImPlotProp prop, Arg arg, Args... args) { + static_assert((sizeof ...(Args)) % 2 == 0, "Odd number of arguments! You must provide (ImPlotProp,value) pairs!"); + SetProp(prop, arg); + SetProp(args...); } // Set a property from a scalar value. @@ -557,52 +556,6 @@ struct ImPlotSpec { } IM_ASSERT(0 && "User provided an ImPlotProp which cannot be set from ImVec4 value!"); } - - // Helper to convert string to enum - static inline ImPlotProp StringToProp(const char* name) { - if (strcmp(name, "LineColor") == 0) return ImPlotProp_LineColor; - if (strcmp(name, "LineWeight") == 0) return ImPlotProp_LineWeight; - if (strcmp(name, "FillColor") == 0) return ImPlotProp_FillColor; - if (strcmp(name, "FillAlpha") == 0) return ImPlotProp_FillAlpha; - if (strcmp(name, "Marker") == 0) return ImPlotProp_Marker; - if (strcmp(name, "MarkerSize") == 0) return ImPlotProp_MarkerSize; - if (strcmp(name, "MarkerLineColor") == 0) return ImPlotProp_MarkerLineColor; - if (strcmp(name, "MarkerFillColor") == 0) return ImPlotProp_MarkerFillColor; - if (strcmp(name, "Size") == 0) return ImPlotProp_Size; - if (strcmp(name, "Offset") == 0) return ImPlotProp_Offset; - if (strcmp(name, "Stride") == 0) return ImPlotProp_Stride; - if (strcmp(name, "Flags") == 0) return ImPlotProp_Flags; - return (ImPlotProp)-1; - } - - // Set property from string and scalar - template - void SetProp(const char* prop_name, T v) { - ImPlotProp prop = StringToProp(prop_name); - if (prop != -1) - SetProp(prop, v); - else - IM_ASSERT(0 && "Invalid ImPlotProp string name!"); - } - - // Set property from string and ImVec4 - void SetProp(const char* prop_name, const ImVec4& v) { - ImPlotProp prop = StringToProp(prop_name); - if (prop != -1) - SetProp(prop, v); - else - IM_ASSERT(0 && "Invalid ImPlotProp string name!"); - } - - // Base case - void Apply() { } - - // Set properties from (ImPlotProp,value) pairs in any order, e.g. SetProp(ImPlotProp_LineColor, my_color, ImPlotProp_Marker, 4.0f) - template - void Apply(Key key, Value val, Args... args) { - SetProp(key, val); - Apply(args...); - } }; // Double precision version of ImVec2 used by ImPlot. Extensible by end users. diff --git a/implot_demo.cpp b/implot_demo.cpp index d5471b0c..add05ee6 100644 --- a/implot_demo.cpp +++ b/implot_demo.cpp @@ -410,11 +410,11 @@ void Demo_ScatterPlots() { if (ImPlot::BeginPlot("Scatter Plot")) { ImPlot::PlotScatter("Data 1", xs1, ys1, 100); ImPlot::PlotScatter("Data 2", xs2, ys2, 50, { - "Marker", ImPlotMarker_Square, - "MarkerSize", 6, - "LineColor", GetColormapColor(1), - "FillColor", GetColormapColor(1), - "FillAlpha", 0.25f + ImPlotProp_Marker, ImPlotMarker_Square, + ImPlotProp_MarkerSize, 6, + ImPlotProp_LineColor, GetColormapColor(1), + ImPlotProp_FillColor, GetColormapColor(1), + ImPlotProp_FillAlpha, 0.25f }); ImPlot::EndPlot(); } @@ -600,7 +600,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::PlotStems("Stems 2", xs, ys2,51, 0, {"Marker", ImPlotMarker_Circle}); + ImPlot::PlotStems("Stems 2", xs, ys2,51, 0, {ImPlotProp_Marker, ImPlotMarker_Circle}); ImPlot::EndPlot(); } } From 712d081797d55edd95b560c76ab1f86277ef1d9e Mon Sep 17 00:00:00 2001 From: Breno Cunha Queiroz Date: Thu, 12 Feb 2026 07:06:44 +0100 Subject: [PATCH 18/21] refactor: increment IMPLOT_VERSION_NUM --- implot.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/implot.h b/implot.h index 2d6760fe..c20a2961 100644 --- a/implot.h +++ b/implot.h @@ -64,7 +64,7 @@ // ImPlot version string. #define IMPLOT_VERSION "0.18 WIP" // ImPlot version integer encoded as XYYZZ (X=major, YY=minor, ZZ=patch). -#define IMPLOT_VERSION_NUM 1800 +#define IMPLOT_VERSION_NUM 1801 // Macro for templated plotting functions; keeps header clean. #define IMPLOT_TMP template IMPLOT_API From 907999280a5f645c43c93f4bf283005a444300e4 Mon Sep 17 00:00:00 2001 From: Breno Cunha Queiroz Date: Thu, 12 Feb 2026 07:28:22 +0100 Subject: [PATCH 19/21] docs: add SetNextXXX to obsolete API section --- implot.cpp | 2 +- implot.h | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/implot.cpp b/implot.cpp index f013312e..096982c2 100644 --- a/implot.cpp +++ b/implot.cpp @@ -32,7 +32,7 @@ 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: +- 2023/10/02 (0.18) - 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. diff --git a/implot.h b/implot.h index c20a2961..1ea10a43 100644 --- a/implot.h +++ b/implot.h @@ -1343,6 +1343,15 @@ enum ImPlotFlagsObsolete_ { namespace ImPlot { +// OBSOLETED in v0.18 (from February 2026) +// IMPLOT_API void SetNextLineStyle(const ImVec4& col = IMPLOT_AUTO_COL, float weight = IMPLOT_AUTO); // OBSOLETED IN 0.18 // Set ImPlotSpec.LineColor/LineWeight or construct ImPlotSpec with { ImPlotSpec_LineColor, color, ImPlotSpec_LineWeight, weight }. + +// IMPLOT_API void SetNextFillStyle(const ImVec4& col = IMPLOT_AUTO_COL, float alpha_mod = IMPLOT_AUTO);// OBSOLETED IN 0.18 // Set ImPlotSpec.FillColor/FillAlpha or construct ImPlotSpec with { ImPlotSpec_FillColor, color, ImPlotSpec_FillAlpha, alpha }. + +// 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); // OBSOLETED IN 0.18 // Set ImPlotSpec.Marker/MarkerSize/MarkerFillColor/LineWeight/MarkerLineColor or construct ImPlotSpec with { ImPlotSpec_Marker, marker, ImPlotSpec_MarkerSize, size, ImPlotSpec_MarkerFillColor, fill_color, ImPlotSpec_LineWeight, weight, ImPlotSpec_MarkerLineColor, outline }. + +// IMPLOT_API void SetNextErrorBarStyle(const ImVec4& col = IMPLOT_AUTO_COL, float size = IMPLOT_AUTO, float weight = IMPLOT_AUTO); // OBSOLETED IN 0.18 // Set ImPlotSpec.LineColor/Size/LineWeight or construct ImPlotSpec with { ImPlotSpec_LineColor, col, ImPlotSpec_Size, size, ImPlotSpec_LineWeight, weight }. + // OBSOLETED in v0.13 -> PLANNED REMOVAL in v1.0 IMPLOT_DEPRECATED( IMPLOT_API bool BeginPlot(const char* title_id, const char* x_label, // = nullptr, From e25dc0b24bbfb1eb48990deeff53c51259f49035 Mon Sep 17 00:00:00 2001 From: Breno Cunha Queiroz Date: Thu, 12 Feb 2026 08:26:13 +0100 Subject: [PATCH 20/21] docs: guide to migrate from SetNextXXX to ImPlotSpec --- implot.cpp | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) diff --git a/implot.cpp b/implot.cpp index 096982c2..588025f2 100644 --- a/implot.cpp +++ b/implot.cpp @@ -32,8 +32,62 @@ 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. +- 2026/02/12 (0.18) - ImPlotSpec replaces the SetNextXXX style functions. The guide below shows show to migrate from SetNextXXX to ImPlotSpec. + - `SetNextLineStyle` has been removed, styling should be set via ImPlotSpec. + ``` + // Before + ImPlot::SetNextLineStyle(line_color, line_weight); + ImPlot::PlotLine("Line", xs, ys, count); + + // After + ImPlotSpec spec; + spec.LineColor = line_color; + spec.LineWeight = line_weight; + ImPlot::PlotLine("Line", xs, ys, count, spec); + ``` + - `SetNextFillStyle` has been removed, styling should be set via ImPlotSpec. + ``` + // Before + ImPlot::SetNextFillStyle(fill_color, fill_alpha); + ImPlot::PlotLine("Shaded", xs, ys, count, ImPlotLineFlags_Shaded); + + // After + ImPlotSpec spec; + spec.FillColor = fill_color; + spec.FillAlpha = fill_alpha; + spec.Flags = ImPlotLineFlags_Shaded; + ImPlot::PlotTLine("Shaded", xs, ys, count, spec); + ``` + - SetNextMarkerStyle has been removed, styling should be set via ImPlotSpec. + ``` + // Before + ImPlot::SetNextMarkerStyle(marker, marker_size, fill_color, line_weight, marker_outline_color); + ImPlot::PlotScatter("Scatter", xs, ys, count); + + // After + ImPlotSpec spec; + spec.LineWeight = line_weight; + spec.Marker = marker; + spec.MarkerSize = marker_size; + spec.MarkerLineColor = marker_outline_color; + spec.MarkerFillColor = fill_color; + ImPlot::PlotScatter("Scatter", xs, ys, count, spec); + ``` + - SetNextErrorBarStyle has been removed, styling should be set via ImPlotSpec. + ``` + // Before + ImPlot::SetNextErrorBarStyle(color, size, weight); + ImPlot::PlotErrorBars("ErrorBar", xs, ys, err, count); + + // After + ImPlotSpec spec; + spec.LineColor = color; + spec.Size = size; + spec.LineWeight = weight; + ImPlot::PlotErrorBars("ErrorBar", xs, ys, err, count, spec); + ``` + - Flags, Offset and Stride should also be set via ImPlotSpec now. - 2023/10/02 (0.18) - 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 From 7935c87a4005d8b39c01ee4476e35758dbd24d53 Mon Sep 17 00:00:00 2001 From: Breno Cunha Queiroz Date: Fri, 13 Feb 2026 12:05:09 +0100 Subject: [PATCH 21/21] refactor: rename PlotBubbles to PlotBubble --- implot.h | 12 ++++++------ implot_demo.cpp | 4 ++-- implot_items.cpp | 16 ++++++++-------- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/implot.h b/implot.h index 87825ed2..115eb01a 100644 --- a/implot.h +++ b/implot.h @@ -94,7 +94,7 @@ typedef int ImPlotColormapScaleFlags; // -> ImPlotColormapScaleFlags_ typedef int ImPlotItemFlags; // -> ImPlotItemFlags_ typedef int ImPlotLineFlags; // -> ImPlotLineFlags_ typedef int ImPlotScatterFlags; // -> ImPlotScatterFlags -typedef int ImPlotBubblesFlags; // -> ImPlotBubblesFlags +typedef int ImPlotBubbleFlags; // -> ImPlotBubbleFlags typedef int ImPlotStairsFlags; // -> ImPlotStairsFlags_ typedef int ImPlotShadedFlags; // -> ImPlotShadedFlags_ typedef int ImPlotBarsFlags; // -> ImPlotBarsFlags_ @@ -266,9 +266,9 @@ enum ImPlotScatterFlags_ { ImPlotScatterFlags_NoClip = 1 << 10, // markers on the edge of a plot will not be clipped }; -// Flags for PlotBubbles. Used by setting ImPlotSpec::Flags. -enum ImPlotBubblesFlags_ { - ImPlotBubblesFlags_None = 0, // default +// Flags for PlotBubble. Used by setting ImPlotSpec::Flags. +enum ImPlotBubbleFlags_ { + ImPlotBubbleFlags_None = 0, // default }; // Flags for PlotStairs. Used by setting ImPlotSpec::Flags. @@ -957,8 +957,8 @@ IMPLOT_TMP void PlotScatter(const char* label_id, const T* xs, const T* ys, int IMPLOT_API void PlotScatterG(const char* label_id, ImPlotGetter getter, void* data, int count, const ImPlotSpec& spec=ImPlotSpec()); // Plots a bubble graph. #szs are the radius of each bubble in plot units. -IMPLOT_TMP void PlotBubbles(const char* label_id, const T* values, const T* szs, int count, double xscale=1, double xstart=0, const ImPlotSpec& spec=ImPlotSpec()); -IMPLOT_TMP void PlotBubbles(const char* label_id, const T* xs, const T* ys, const T* szs, int count, const ImPlotSpec& spec=ImPlotSpec()); +IMPLOT_TMP void PlotBubble(const char* label_id, const T* values, const T* szs, int count, double xscale=1, double xstart=0, const ImPlotSpec& spec=ImPlotSpec()); +IMPLOT_TMP void PlotBubble(const char* label_id, const T* xs, const T* ys, const T* szs, 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, const ImPlotSpec& spec=ImPlotSpec()); diff --git a/implot_demo.cpp b/implot_demo.cpp index 88a87e7a..cf6bc402 100644 --- a/implot_demo.cpp +++ b/implot_demo.cpp @@ -436,8 +436,8 @@ void Demo_BubblePlots() { if (ImPlot::BeginPlot("Bubble Plot", ImVec2(-1,0), ImPlotFlags_Equal)) { - ImPlot::PlotBubbles("Data 1", xs, ys1, szs1, 20, {ImPlotProp_FillAlpha, 0.5f}); - ImPlot::PlotBubbles("Data 2", xs, ys2, szs2, 20, {ImPlotProp_FillAlpha, 0.5f, ImPlotProp_LineColor, ImVec4(0,0,0,0.0)}); + ImPlot::PlotBubble("Data 1", xs, ys1, szs1, 20, {ImPlotProp_FillAlpha, 0.5f}); + ImPlot::PlotBubble("Data 2", xs, ys2, szs2, 20, {ImPlotProp_FillAlpha, 0.5f, ImPlotProp_LineColor, ImVec4(0,0,0,0.0)}); ImPlot::EndPlot(); } diff --git a/implot_items.cpp b/implot_items.cpp index 1af0cd2c..dd7a1c5b 100644 --- a/implot_items.cpp +++ b/implot_items.cpp @@ -1898,11 +1898,11 @@ void PlotScatterG(const char* label_id, ImPlotGetter getter_func, void* data, in } //----------------------------------------------------------------------------- -// [SECTION] PlotBubbles +// [SECTION] PlotBubble //----------------------------------------------------------------------------- template -void PlotBubblesEx(const char* label_id, const Getter& getter, const ImPlotSpec& spec) { +void PlotBubbleEx(const char* label_id, const Getter& getter, const ImPlotSpec& spec) { if (BeginItemEx(label_id, FitterBubbles1(getter), spec, spec.FillColor, spec.Marker)) { if (getter.Count <= 0) { EndItem(); @@ -1924,20 +1924,20 @@ void PlotBubblesEx(const char* label_id, const Getter& getter, const ImPlotSpec& } template -void PlotBubbles(const char* label_id, const T* values, const T* szs, int count, double xscale, double x0, const ImPlotSpec& spec) { +void PlotBubble(const char* label_id, const T* values, const T* szs, int count, double xscale, double x0, const ImPlotSpec& spec) { GetterXYZ,IndexerIdx> getter(IndexerLin(xscale,x0), IndexerIdx(values,count,spec.Offset,Stride(spec)), IndexerIdx(szs,count,spec.Offset,Stride(spec)),count); - PlotBubblesEx(label_id, getter, spec); + PlotBubbleEx(label_id, getter, spec); } template -void PlotBubbles(const char* label_id, const T* xs, const T* ys, const T* szs, int count, const ImPlotSpec& spec) { +void PlotBubble(const char* label_id, const T* xs, const T* ys, const T* szs, int count, const ImPlotSpec& spec) { GetterXYZ,IndexerIdx,IndexerIdx> getter(IndexerIdx(xs,count,spec.Offset,Stride(spec)),IndexerIdx(ys,count,spec.Offset,Stride(spec)), IndexerIdx(szs,count,spec.Offset,Stride(spec)),count); - return PlotBubblesEx(label_id, getter, spec); + return PlotBubbleEx(label_id, getter, spec); } #define INSTANTIATE_MACRO(T) \ - template IMPLOT_API void PlotBubbles(const char* label_id, const T* values, const T* szs, int count, double xscale, double x0, const ImPlotSpec& spec); \ - template IMPLOT_API void PlotBubbles(const char* label_id, const T* xs, const T* ys, const T* szs, int count, const ImPlotSpec& spec); + template IMPLOT_API void PlotBubble(const char* label_id, const T* values, const T* szs, int count, double xscale, double x0, const ImPlotSpec& spec); \ + template IMPLOT_API void PlotBubble(const char* label_id, const T* xs, const T* ys, const T* szs, int count, const ImPlotSpec& spec); CALL_INSTANTIATE_FOR_NUMERIC_TYPES() #undef INSTANTIATE_MACRO