From 76af1130185cb81eb989940d206444d84084fe20 Mon Sep 17 00:00:00 2001 From: epezent Date: Sat, 30 Sep 2023 11:33:52 -0500 Subject: [PATCH] Make markers automatically cycle; adopt constexpr --- implot.cpp | 53 +++++++++++++++++------------- implot.h | 19 +++++++---- implot_demo.cpp | 10 +++--- implot_internal.h | 44 ++++++++++++++++--------- implot_items.cpp | 82 ++++++++++++++++++++++++++++------------------- 5 files changed, 124 insertions(+), 84 deletions(-) diff --git a/implot.cpp b/implot.cpp index 7a229e30..bd9ec91d 100644 --- a/implot.cpp +++ b/implot.cpp @@ -235,6 +235,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"; @@ -687,8 +688,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) @@ -824,7 +825,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, @@ -836,7 +837,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; @@ -856,28 +857,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; @@ -1801,8 +1802,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) { @@ -3245,9 +3246,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; @@ -3871,7 +3872,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"); @@ -4458,6 +4459,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 //------------------------------------------------------------------------------ @@ -4531,7 +4540,7 @@ ImU32 NextColormapColorU32() { ImVec4 NextColormapColor() { return ImGui::ColorConvertU32ToFloat4(NextColormapColorU32()); -} +} int GetColormapSize(ImPlotColormap cmap) { ImPlotContext& gp = *GImPlot; @@ -5283,7 +5292,7 @@ void ShowMetricsWindow(bool* p_popen) { ImVec4 temp = ImGui::ColorConvertU32ToFloat4(item->Color); if (ImGui::ColorEdit4("Color",&temp.x, ImGuiColorEditFlags_NoInputs)) item->Color = ImGui::ColorConvertFloat4ToU32(temp); - + ImGui::BulletText("Marker: %s", GetMarkerName(item->Marker)); ImGui::BulletText("NameOffset: %d",item->NameOffset); ImGui::BulletText("Name: %s", item->NameOffset != -1 ? plot.Items.Legend.Labels.Buf.Data + item->NameOffset : "N/A"); ImGui::BulletText("Hovered: %s",item->LegendHovered ? "true" : "false"); diff --git a/implot.h b/implot.h index 4e97cb8a..cad656d4 100644 --- a/implot.h +++ b/implot.h @@ -61,13 +61,14 @@ // ImPlot version string. #define IMPLOT_VERSION "0.17" -// Indicates variable should deduced automatically. -#define IMPLOT_AUTO -1 -// Special color used to indicate that a color should be deduced automatically. -#define IMPLOT_AUTO_COL ImVec4(0,0,0,-1) // Macro for templated plotting functions; keeps header clean. #define IMPLOT_TMP template IMPLOT_API +// Indicates variable should deduced automatically. +constexpr int IMPLOT_AUTO = -1; +// Special color used to indicate that a color should be deduced automatically. +constexpr ImVec4 IMPLOT_AUTO_COL = ImVec4(0,0,0,-1); + //----------------------------------------------------------------------------- // [SECTION] Enums and Types //----------------------------------------------------------------------------- @@ -407,7 +408,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 @@ -1143,7 +1145,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 //----------------------------------------------------------------------------- @@ -1213,7 +1218,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 894d8bea..0ee849a6 100644 --- a/implot_demo.cpp +++ b/implot_demo.cpp @@ -434,12 +434,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(); @@ -576,7 +576,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(); } @@ -943,7 +943,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"); @@ -958,7 +958,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(); @@ -968,7 +967,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 86149cd6..89a34a64 100644 --- a/implot_internal.h +++ b/implot_internal.h @@ -51,22 +51,25 @@ // Constants can be changed unless stated otherwise. We may move some of these // to ImPlotStyleVar_ over time. -// Mimimum allowable timestamp value 01/01/1970 @ 12:00am (UTC) (DO NOT DECREASE THIS) -#define IMPLOT_MIN_TIME 0 +// Minimum allowable timestamp value 01/01/1970 @ 12:00am (UTC) (DO NOT DECREASE THIS) +constexpr double IMPLOT_MIN_TIME = 0; // Maximum allowable timestamp value 01/01/3000 @ 12:00am (UTC) (DO NOT INCREASE THIS) -#define IMPLOT_MAX_TIME 32503680000 +constexpr double IMPLOT_MAX_TIME = 32503680000; + // Default label format for axis labels -#define IMPLOT_LABEL_FORMAT "%g" +constexpr const char* IMPLOT_LABEL_FORMAT = "%g"; // Max character size for tick labels -#define IMPLOT_LABEL_MAX_SIZE 32 +constexpr int IMPLOT_LABEL_MAX_SIZE = 32; + +// Number of X axes +constexpr int IMPLOT_NUM_X_AXES = ImAxis_Y1; +// Number of Y axes +constexpr int IMPLOT_NUM_Y_AXES = ImAxis_COUNT - IMPLOT_NUM_X_AXES; //----------------------------------------------------------------------------- // [SECTION] Macros //----------------------------------------------------------------------------- -#define IMPLOT_NUM_X_AXES ImAxis_Y1 -#define IMPLOT_NUM_Y_AXES (ImAxis_COUNT - IMPLOT_NUM_X_AXES) - // Split ImU32 color into RGB components [0 255] #define IM_COL32_SPLIT_RGB(col,r,g,b) \ ImU32 r = ((col >> IM_COL32_R_SHIFT) & 0xFF); \ @@ -226,9 +229,10 @@ static inline bool ImOverlaps(T min_a, T max_a, T min_b, T max_b) { // [SECTION] ImPlot Enums //----------------------------------------------------------------------------- -typedef int ImPlotTimeUnit; // -> enum ImPlotTimeUnit_ -typedef int ImPlotDateFmt; // -> enum ImPlotDateFmt_ -typedef int ImPlotTimeFmt; // -> enum ImPlotTimeFmt_ +typedef int ImPlotTimeUnit; // -> enum ImPlotTimeUnit_ +typedef int ImPlotDateFmt; // -> enum ImPlotDateFmt_ +typedef int ImPlotTimeFmt; // -> enum ImPlotTimeFmt_ +typedef int ImPlotMarkerInternal; // -> enum ImPlotMarkerInternal_ enum ImPlotTimeUnit_ { ImPlotTimeUnit_Us, // microsecond @@ -264,6 +268,10 @@ enum ImPlotTimeFmt_ { // default [ 24 Hour Clock ] ImPlotTimeFmt_Hr // 7pm [ 19:00 ] }; +enum ImPlotMarkerInternal_ { + ImPlotMarker_Invalid = -3 +}; + //----------------------------------------------------------------------------- // [SECTION] Callbacks //----------------------------------------------------------------------------- @@ -941,6 +949,7 @@ struct ImPlotItem { ImGuiID ID; ImU32 Color; + ImPlotMarker Marker; ImRect LegendHoverRect; int NameOffset; bool Show; @@ -950,6 +959,7 @@ struct ImPlotItem ImPlotItem() { ID = 0; Color = IM_COL32_WHITE; + Marker = ImPlotMarker_None; NameOffset = -1; Show = true; SeenThisFrame = false; @@ -993,8 +1003,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 */ } @@ -1178,6 +1189,7 @@ struct ImPlotNextItemData { float DigitalBitGap; // TODO: remove bool RenderLine; bool RenderFill; + bool RenderMarkers; bool HasHidden; bool Hidden; ImPlotCond HiddenCond; @@ -1297,12 +1309,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]); @@ -1535,7 +1547,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 ac4afee5..ca56f629 100644 --- a/implot_items.cpp +++ b/implot_items.cpp @@ -365,11 +365,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(); @@ -379,14 +379,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(); @@ -401,6 +414,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; @@ -421,6 +435,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; @@ -1448,15 +1463,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), @@ -1478,15 +1493,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) { @@ -1523,7 +1538,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; @@ -1555,7 +1570,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); @@ -1598,21 +1613,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(); } @@ -1648,7 +1664,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; @@ -1671,7 +1687,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); @@ -2051,7 +2067,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; @@ -2063,7 +2079,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);