From 6fe7bec600227dedc28c38b602735d958bf5187f Mon Sep 17 00:00:00 2001 From: dracir9 Date: Sun, 8 Mar 2026 22:22:23 +0100 Subject: [PATCH 1/2] feat: add support for line styles (#185) * feat: add LineStyle variable to ImPlotSpec * feat: add RendererLineStripUV to render textured liens * feat: add AddLineStyle to register custom line styles * docs: added line style demo tab --- implot.cpp | 71 +++++++++++++++++++++++++++++++++ implot.h | 19 +++++++++ implot_demo.cpp | 31 +++++++++++++++ implot_internal.h | 26 ++++++++++--- implot_items.cpp | 99 +++++++++++++++++++++++++++++++++++++++++++++-- 5 files changed, 237 insertions(+), 9 deletions(-) diff --git a/implot.cpp b/implot.cpp index e33613b7..c5c77430 100644 --- a/implot.cpp +++ b/implot.cpp @@ -4556,6 +4556,77 @@ ImPlotMarker NextMarker() { ++gp.CurrentItems->MarkerIdx; return idx; } + +void LoadDefaultLineStyles() { + const ImU32 Dash[] = {10, 6}; + const ImU32 Dot[] = {2, 6}; + const ImU32 DashDot[] = {10, 6, 2, 6}; + const ImU32 DashDotDot[] = {10, 6, 2, 6, 2, 6}; + + AddLineStyle(Dash, sizeof(Dash)/sizeof(ImU32)); + AddLineStyle(Dot, sizeof(Dot)/sizeof(ImU32)); + AddLineStyle(DashDot, sizeof(DashDot)/sizeof(ImU32)); + AddLineStyle(DashDotDot, sizeof(DashDotDot)/sizeof(ImU32)); +} + +int AddLineStyle(const ImU32* keys, int count) { + ImPlotContext& gp = *GImPlot; + IM_ASSERT_USER_ERROR(count > 1, "The line style size must be greater than 1!"); + int period = 0; + for (int i = 0; i < count; ++i){ + period += keys[i]; + } + // Get font atlas and add a custom rectangle to it + ImFontAtlas *atlas = ImGui::GetIO().Fonts; + ImFontAtlasRectId rectID = atlas->AddCustomRect(510, 1); + int keyIdx = 0; + ImU32 k = 0; + ImU32 color = ~0; + if (rectID != -1) + { + // Build the atlas and get the pixel data + unsigned char* pixels; + int width, height; + atlas->GetTexDataAsRGBA32(&pixels, &width, &height); + // Retrieve the rectangle location and fill it with data + ImFontAtlasRect rect; + if (atlas->GetCustomRect(rectID, &rect)) + { + for (int i = 0; i < rect.h; i++) + { + // Calculate the pointer to the start of the row in the atlas + ImU32* row = (ImU32*)pixels + (rect.y + i) * width + rect.x; + for (int j = 0; j < rect.w; j++) + { + row[j] = color; + if (++k >= keys[keyIdx]) { + color = ~color; + keyIdx = (keyIdx + 1) % count; + k = 0; + } + } + } + ImPlotLineStyleData data(rectID, period, 510); + gp.LineStyleData.push_back(data); + return gp.LineStyleData.Size - 1; + } + else + IM_ASSERT(0 && "Failed to retrieve custom rectangle from font atlas for line style!"); + } + else + IM_ASSERT(0 && "Failed to add custom rectangle to font atlas for line style!"); + + return -1; +} + +const ImPlotLineStyleData& GetLineStyleData(ImPlotLineStyle style) { + ImPlotContext& gp = *GImPlot; + IM_ASSERT_USER_ERROR(style >= 0 && style < gp.LineStyleData.Size, "Invalid line style index!"); + const ImPlotLineStyleData& data = gp.LineStyleData[style]; + if (!ImGui::GetIO().Fonts->GetCustomRect(data.RectID, &data.Rect)) + IM_ASSERT(0 && "Failed to retrieve custom rectangle from font atlas for line style!"); + return data; +} //------------------------------------------------------------------------------ // [Section] Colormaps diff --git a/implot.h b/implot.h index 2c995a80..ccea2c36 100644 --- a/implot.h +++ b/implot.h @@ -115,6 +115,7 @@ typedef int ImPlotCond; // -> enum ImPlotCond_ typedef int ImPlotCol; // -> enum ImPlotCol_ typedef int ImPlotStyleVar; // -> enum ImPlotStyleVar_ typedef int ImPlotScale; // -> enum ImPlotScale_ +typedef int ImPlotLineStyle; // -> enum ImPlotLineStyle_ typedef int ImPlotMarker; // -> enum ImPlotMarker_ typedef int ImPlotColormap; // -> enum ImPlotColormap_ typedef int ImPlotLocation; // -> enum ImPlotLocation_ @@ -139,6 +140,7 @@ enum ImAxis_ { enum ImPlotProp_ { 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_LineStyle, // line style (applies to lines) 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 @@ -429,6 +431,16 @@ enum ImPlotScale_ { ImPlotScale_SymLog, // symmetric log scale }; +// Line style specifications. +enum ImPlotLineStyle_ { + ImPlotLineStyle_Solid = -1,// default + ImPlotLineStyle_Dashed, // 6px on, 6px off + ImPlotLineStyle_Dotted, // 2px on, 6px off + ImPlotLineStyle_DashDot, // 6px on, 2px off, 2px on, 2px off + ImPlotLineStyle_DashDotDot,// 6px on, 2px off, 2px on, 2px off, 2px on, 2px off + ImPlotLineStyle_COUNT +}; + // Marker specifications. enum ImPlotMarker_ { ImPlotMarker_None = -2, // no marker @@ -510,6 +522,7 @@ enum ImPlotBin_ { 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) + ImPlotLineStyle LineStyle = ImPlotLineStyle_Solid; // line style (applies to lines) 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 @@ -544,6 +557,7 @@ struct ImPlotSpec { switch (prop) { case ImPlotProp_LineColor : LineColor = ImGui::ColorConvertU32ToFloat4((ImU32)v); return; case ImPlotProp_LineWeight : LineWeight = (float)v; return; + case ImPlotProp_LineStyle : LineStyle = (ImPlotLineStyle)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; @@ -1216,6 +1230,11 @@ 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(); +// Executes post-setup initialization +IMPLOT_API void LoadDefaultLineStyles(); + +IMPLOT_API int AddLineStyle(const ImU32* keys, int count); + //----------------------------------------------------------------------------- // [SECTION] Colormaps //----------------------------------------------------------------------------- diff --git a/implot_demo.cpp b/implot_demo.cpp index 2ff2a027..cef5da16 100644 --- a/implot_demo.cpp +++ b/implot_demo.cpp @@ -1063,6 +1063,36 @@ void Demo_RealtimePlots() { //----------------------------------------------------------------------------- +void Demo_LineStyles() { + IMGUI_DEMO_MARKER("Plots/Line Styles"); + // ImPlot::LoadDefaultLineStyles() must be called before using line styles! + // It should be called once during font loading. + static ImPlotSpec spec; + ImGui::DragFloat("Line Weight", &spec.LineWeight,0.05f,0.5f,32.0f,"%.2f px"); + + if (ImPlot::BeginPlot("##LineStyles", ImVec2(-1,0), ImPlotFlags_CanvasOnly)) { + + ImPlot::SetupAxes(nullptr, nullptr, ImPlotAxisFlags_NoDecorations, ImPlotAxisFlags_NoDecorations); + ImPlot::SetupAxesLimits(0, 5, 0, 7); + + ImS8 xs[2] = {1,4}; + ImS8 ys[2] = {5,6}; + + // Line Styles + for (int m = 0; m < ImPlotLineStyle_COUNT; ++m) { + ImGui::PushID(m); + spec.LineStyle = (ImPlotLineStyle)m; + ImPlot::PlotLine("##Style", xs, ys, 2, spec); + ImGui::PopID(); + ys[0]--; ys[1]--; + } + + ImPlot::EndPlot(); + } +} + +//----------------------------------------------------------------------------- + void Demo_MarkersAndText() { IMGUI_DEMO_MARKER("Plots/Markers and Text"); static ImPlotSpec spec(ImPlotProp_Marker, ImPlotMarker_Auto); @@ -2499,6 +2529,7 @@ void ShowDemoWindow(bool* p_open) { DemoHeader("Histogram 2D", Demo_Histogram2D); DemoHeader("Digital Plots", Demo_DigitalPlots); DemoHeader("Images", Demo_Images); + DemoHeader("Line Styles", Demo_LineStyles); DemoHeader("Markers and Text", Demo_MarkersAndText); DemoHeader("NaN Values", Demo_NaNValues); ImGui::EndTabItem(); diff --git a/implot_internal.h b/implot_internal.h index da49cedb..8a040167 100644 --- a/implot_internal.h +++ b/implot_internal.h @@ -123,6 +123,8 @@ template static inline T ImRemap01(T x, T x0, T x1) { return (x - x0) / (x1 - x0); } // Returns always positive modulo (assumes r != 0) static inline int ImPosMod(int l, int r) { return (l % r + r) % r; } +// Returns the modulo of x by y (assumes y != 0) +static inline double ImMod(double x, double y) { return fmod(x, y); } // Returns true if val is NAN static inline bool ImNan(double val) { return isnan(val); } // Returns true if val is NAN or INFINITY @@ -285,6 +287,17 @@ typedef void (*ImPlotLocator)(ImPlotTicker& ticker, const ImPlotRange& range, fl // [SECTION] Structs //----------------------------------------------------------------------------- +struct ImPlotLineStyleData { + ImPlotLineStyleData(ImFontAtlasRectId rect_id, float period, float max_length) : + RectID(rect_id), + Period(period), + MaxLength(max_length) {} + const ImFontAtlasRectId RectID; // texture atlas rect ID for line style + const float Period; // period of line style in pixels + const float MaxLength; // maximum length of line style in pixels + mutable ImFontAtlasRect Rect; // cached rectangle for line style (filled in on demand) +}; + // Combined date/time format spec struct ImPlotDateTimeSpec { ImPlotDateTimeSpec() {} @@ -1243,11 +1256,12 @@ struct ImPlotContext { ImPlotTagCollection Tags; // Style and Colormaps - ImPlotStyle Style; - ImVector ColorModifiers; - ImVector StyleModifiers; - ImPlotColormapData ColormapData; - ImVector ColormapModifiers; + ImPlotStyle Style; + ImVector ColorModifiers; + ImVector StyleModifiers; + ImPlotColormapData ColormapData; + ImVector ColormapModifiers; + ImVector LineStyleData; // Time tm Tm; @@ -1508,6 +1522,8 @@ IMPLOT_API ImU32 SampleColormapU32(float t, ImPlotColormap cmap); // Render a colormap bar IMPLOT_API void RenderColorBar(const ImU32* colors, int size, ImDrawList& DrawList, const ImRect& bounds, bool vert, bool reversed, bool continuous); +IMPLOT_API const ImPlotLineStyleData& GetLineStyleData(ImPlotLineStyle style); + //----------------------------------------------------------------------------- // [SECTION] Math and Misc Utils //----------------------------------------------------------------------------- diff --git a/implot_items.cpp b/implot_items.cpp index 4df2ea9e..c087bcf8 100644 --- a/implot_items.cpp +++ b/implot_items.cpp @@ -204,6 +204,40 @@ IMPLOT_INLINE void PrimLine(ImDrawList& draw_list, const ImVec2& P1, const ImVec draw_list._VtxCurrentIdx += 4; } +IMPLOT_INLINE void PrimLineUV(ImDrawList& draw_list, const ImVec2& P1, const ImVec2& P2, float half_weight, ImU32 col, const ImVec2& uv_a, const ImVec2 uv_c) { + float dx = P2.x - P1.x; + float dy = P2.y - P1.y; + ImVec2 uv_b(uv_c.x, uv_a.y), uv_d(uv_a.x, uv_c.y); + IMPLOT_NORMALIZE2F_OVER_ZERO(dx, dy); + dx *= half_weight; + dy *= half_weight; + draw_list._VtxWritePtr[0].pos.x = P1.x + dy; + draw_list._VtxWritePtr[0].pos.y = P1.y - dx; + draw_list._VtxWritePtr[0].uv = uv_a; + draw_list._VtxWritePtr[0].col = col; + draw_list._VtxWritePtr[1].pos.x = P2.x + dy; + draw_list._VtxWritePtr[1].pos.y = P2.y - dx; + draw_list._VtxWritePtr[1].uv = uv_b; + draw_list._VtxWritePtr[1].col = col; + draw_list._VtxWritePtr[2].pos.x = P2.x - dy; + draw_list._VtxWritePtr[2].pos.y = P2.y + dx; + draw_list._VtxWritePtr[2].uv = uv_c; + draw_list._VtxWritePtr[2].col = col; + draw_list._VtxWritePtr[3].pos.x = P1.x - dy; + draw_list._VtxWritePtr[3].pos.y = P1.y + dx; + draw_list._VtxWritePtr[3].uv = uv_d; + draw_list._VtxWritePtr[3].col = col; + draw_list._VtxWritePtr += 4; + draw_list._IdxWritePtr[0] = (ImDrawIdx)(draw_list._VtxCurrentIdx); + draw_list._IdxWritePtr[1] = (ImDrawIdx)(draw_list._VtxCurrentIdx + 1); + draw_list._IdxWritePtr[2] = (ImDrawIdx)(draw_list._VtxCurrentIdx + 2); + draw_list._IdxWritePtr[3] = (ImDrawIdx)(draw_list._VtxCurrentIdx); + draw_list._IdxWritePtr[4] = (ImDrawIdx)(draw_list._VtxCurrentIdx + 2); + draw_list._IdxWritePtr[5] = (ImDrawIdx)(draw_list._VtxCurrentIdx + 3); + draw_list._IdxWritePtr += 6; + draw_list._VtxCurrentIdx += 4; +} + IMPLOT_INLINE void PrimRectFill(ImDrawList& draw_list, const ImVec2& Pmin, const ImVec2& Pmax, ImU32 col, const ImVec2& uv) { draw_list._VtxWritePtr[0].pos = Pmin; draw_list._VtxWritePtr[0].uv = uv; @@ -949,6 +983,55 @@ struct RendererLineStrip : RendererBase { mutable ImVec2 UV1; }; +template +struct RendererLineStripUV : RendererBase { + RendererLineStripUV(const _Getter& getter, ImU32 col, ImPlotLineStyleData style_data, float weight) : + RendererBase(getter.Count - 1, 6, 4), + Getter(getter), + Col(col), + StyleData(style_data), + HalfWeight(ImMax(1.0f,weight)*0.5f), + cumLen(0.f) + { + 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]); + float segLen; + if (!(ImNan(P1.x) || ImNan(P1.y) || ImNan(P2.x) || ImNan(P2.y))) + segLen = ImSqrt(ImLengthSqr(P2 - P1)); + else + segLen = 0.f; + + if (!cull_rect.Overlaps(ImRect(ImMin(P1, P2), ImMax(P1, P2)))) { + cumLen = ImMod(cumLen + segLen, StyleData.Period); + P1 = P2; + return false; + } + UV0.x = ImRemap(cumLen, 0.f, StyleData.MaxLength, StyleData.Rect.uv0.x, StyleData.Rect.uv1.x); + UV1.x = ImRemap(cumLen + segLen, 0.f, StyleData.MaxLength, StyleData.Rect.uv0.x, StyleData.Rect.uv1.x); + UV0.y = StyleData.Rect.uv0.y; + UV1.y = StyleData.Rect.uv1.y; + + PrimLineUV(draw_list,P1,P2,HalfWeight,Col,UV0,UV1); + + cumLen = ImMod(cumLen + segLen, StyleData.Period); + P1 = P2; + return true; + } + const _Getter& Getter; + const ImU32 Col; + const ImPlotLineStyleData StyleData; + mutable float HalfWeight; + mutable float cumLen; + mutable ImVec2 P1; + mutable ImVec2 UV0; + mutable ImVec2 UV1; +}; + template struct RendererLineStripSkip : RendererBase { RendererLineStripSkip(const _Getter& getter, ImU32 col, float weight) : @@ -1796,14 +1879,22 @@ void PlotLineEx(const char* label_id, const _Getter& getter, const ImPlotSpec& s 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.Spec.LineWeight); + else { + if (s.Spec.LineStyle == ImPlotLineStyle_Solid) + RenderPrimitives1(GetterLoop<_Getter>(getter),col_line,s.Spec.LineWeight); + else + RenderPrimitives1(GetterLoop<_Getter>(getter),col_line,GetLineStyleData(s.Spec.LineStyle), s.Spec.LineWeight); + } } else { if (ImHasFlag(spec.Flags, ImPlotLineFlags_SkipNaN)) RenderPrimitives1(getter,col_line,s.Spec.LineWeight); - else - RenderPrimitives1(getter,col_line,s.Spec.LineWeight); + else { + if (s.Spec.LineStyle == ImPlotLineStyle_Solid) + RenderPrimitives1(getter,col_line,s.Spec.LineWeight); + else + RenderPrimitives1(getter,col_line,GetLineStyleData(s.Spec.LineStyle),s.Spec.LineWeight); + } } } } From 8f72b68932de63b0007614025ff042765abb9415 Mon Sep 17 00:00:00 2001 From: dracir9 Date: Mon, 9 Mar 2026 22:48:36 +0100 Subject: [PATCH 2/2] refactor: add AddLineStyleInternal to register new line styles * feat: AddLineStyle can now be called before LoadDefaultLineStyles * docs: Added custom line styles demo code --- implot.cpp | 33 +++++++++++++++++++++++++-------- implot_demo.cpp | 34 +++++++++++++++++++++++++++++----- implot_internal.h | 13 +++++++++---- 3 files changed, 63 insertions(+), 17 deletions(-) diff --git a/implot.cpp b/implot.cpp index c5c77430..06ae78d1 100644 --- a/implot.cpp +++ b/implot.cpp @@ -4563,19 +4563,34 @@ void LoadDefaultLineStyles() { const ImU32 DashDot[] = {10, 6, 2, 6}; const ImU32 DashDotDot[] = {10, 6, 2, 6, 2, 6}; - AddLineStyle(Dash, sizeof(Dash)/sizeof(ImU32)); - AddLineStyle(Dot, sizeof(Dot)/sizeof(ImU32)); - AddLineStyle(DashDot, sizeof(DashDot)/sizeof(ImU32)); - AddLineStyle(DashDotDot, sizeof(DashDotDot)/sizeof(ImU32)); + // The default line styles are added at fixed indices + // We use the internal add function with the desired index to ensure they are stored in the correct order and that user defined line styles are added after them + AddLineStyleInternal(ImPlotLineStyle_Dashed, Dash, sizeof(Dash)/sizeof(ImU32)); + AddLineStyleInternal(ImPlotLineStyle_Dotted, Dot, sizeof(Dot)/sizeof(ImU32)); + AddLineStyleInternal(ImPlotLineStyle_DashDot, DashDot, sizeof(DashDot)/sizeof(ImU32)); + AddLineStyleInternal(ImPlotLineStyle_DashDotDot, DashDotDot, sizeof(DashDotDot)/sizeof(ImU32)); } int AddLineStyle(const ImU32* keys, int count) { + IM_ASSERT_USER_ERROR(count > 1 && count % 2 == 0, "The line style size must be greater than 1 and even!"); + // User defined line styles are added after the default line styles, so we start with an index of -1 to append to the end of the list + return AddLineStyleInternal(-1, keys, count); +} + +int AddLineStyleInternal(const int ID, const ImU32* keys, const int count) { + IM_ASSERT(ID < ImPlotLineStyle_COUNT || ID == -1); // ID must be a valid default line style index or -1 for user defined styles ImPlotContext& gp = *GImPlot; - IM_ASSERT_USER_ERROR(count > 1, "The line style size must be greater than 1!"); int period = 0; for (int i = 0; i < count; ++i){ period += keys[i]; } + // Reserve space for default line styles if they haven't been added yet + if (gp.LineStyleData.Size < ImPlotLineStyle_COUNT) { + gp.LineStyleData.resize(ImPlotLineStyle_COUNT); + for (int i = 0; i < ImPlotLineStyle_COUNT; ++i) gp.LineStyleData[i].RectID = -1; + } + if (ID >= 0 && gp.LineStyleData[ID].RectID != -1) + return ID; // If the ID is already used // Get font atlas and add a custom rectangle to it ImFontAtlas *atlas = ImGui::GetIO().Fonts; ImFontAtlasRectId rectID = atlas->AddCustomRect(510, 1); @@ -4606,8 +4621,11 @@ int AddLineStyle(const ImU32* keys, int count) { } } } - ImPlotLineStyleData data(rectID, period, 510); - gp.LineStyleData.push_back(data); + // Add the line style data to the context + if (ID < 0) + gp.LineStyleData.push_back(ImPlotLineStyleData(rectID, period, 510)); + else + gp.LineStyleData[ID] = ImPlotLineStyleData(rectID, period, 510); return gp.LineStyleData.Size - 1; } else @@ -4615,7 +4633,6 @@ int AddLineStyle(const ImU32* keys, int count) { } else IM_ASSERT(0 && "Failed to add custom rectangle to font atlas for line style!"); - return -1; } diff --git a/implot_demo.cpp b/implot_demo.cpp index cef5da16..dcbdb82d 100644 --- a/implot_demo.cpp +++ b/implot_demo.cpp @@ -1065,18 +1065,35 @@ void Demo_RealtimePlots() { void Demo_LineStyles() { IMGUI_DEMO_MARKER("Plots/Line Styles"); - // ImPlot::LoadDefaultLineStyles() must be called before using line styles! - // It should be called once during font loading. static ImPlotSpec spec; + static bool is_init = false; + static ImPlotLineStyle custom_style[2]; + // Custom line styles are defined by an array of on/off lengths in pixels. + // The first element is the length of the dash, the second is the length of the gap, and so on. + static ImU32 styleA[] = {15, 6, 15, 6, 2, 6}; // dash, dash, dot + static ImU32 styleB[] = {20, 6, 10, 6}; // long dash, short dash + + // ImPlot::LoadDefaultLineStyles() must be called before using line styles! + // It should be called once after context creation and backend initialization + // Called here for demo purposes, but you should call it in your initialization code. + if (!is_init) { + // Register custom line style before loading defaults + custom_style[0] = ImPlot::AddLineStyle(styleA, sizeof(styleA)/sizeof(ImU32)); + // Load default line styles + ImPlot::LoadDefaultLineStyles(); + // Register custom line style after loading defaults (order doesn't matter) + custom_style[1] = ImPlot::AddLineStyle(styleB, sizeof(styleB)/sizeof(ImU32)); + is_init = true; + } ImGui::DragFloat("Line Weight", &spec.LineWeight,0.05f,0.5f,32.0f,"%.2f px"); if (ImPlot::BeginPlot("##LineStyles", ImVec2(-1,0), ImPlotFlags_CanvasOnly)) { ImPlot::SetupAxes(nullptr, nullptr, ImPlotAxisFlags_NoDecorations, ImPlotAxisFlags_NoDecorations); - ImPlot::SetupAxesLimits(0, 5, 0, 7); + ImPlot::SetupAxesLimits(0, 5, 0, 9); ImS8 xs[2] = {1,4}; - ImS8 ys[2] = {5,6}; + ImS8 ys[2] = {7,8}; // Line Styles for (int m = 0; m < ImPlotLineStyle_COUNT; ++m) { @@ -1086,7 +1103,14 @@ void Demo_LineStyles() { ImGui::PopID(); ys[0]--; ys[1]--; } - + // Custom Line Styles + for (int m = 0; m < 2; ++m) { + ImGui::PushID(m); + spec.LineStyle = custom_style[m]; + ImPlot::PlotLine("##Custom", xs, ys, 2, spec); + ImGui::PopID(); + ys[0]--; ys[1]--; + } ImPlot::EndPlot(); } } diff --git a/implot_internal.h b/implot_internal.h index 8a040167..f7b413de 100644 --- a/implot_internal.h +++ b/implot_internal.h @@ -288,14 +288,15 @@ typedef void (*ImPlotLocator)(ImPlotTicker& ticker, const ImPlotRange& range, fl //----------------------------------------------------------------------------- struct ImPlotLineStyleData { + ImPlotLineStyleData() {} ImPlotLineStyleData(ImFontAtlasRectId rect_id, float period, float max_length) : RectID(rect_id), Period(period), MaxLength(max_length) {} - const ImFontAtlasRectId RectID; // texture atlas rect ID for line style - const float Period; // period of line style in pixels - const float MaxLength; // maximum length of line style in pixels - mutable ImFontAtlasRect Rect; // cached rectangle for line style (filled in on demand) + ImFontAtlasRectId RectID; // texture atlas rect ID for line style + float Period; // period of line style in pixels + float MaxLength; // maximum length of line style in pixels + mutable ImFontAtlasRect Rect; // cached rectangle for line style (filled in on demand) }; // Combined date/time format spec @@ -1522,6 +1523,10 @@ IMPLOT_API ImU32 SampleColormapU32(float t, ImPlotColormap cmap); // Render a colormap bar IMPLOT_API void RenderColorBar(const ImU32* colors, int size, ImDrawList& DrawList, const ImRect& bounds, bool vert, bool reversed, bool continuous); +// Adds a line style with the given ID to ImPlot context. Set ID to -1 to add a line style with an automatically generated ID. +IMPLOT_API int AddLineStyleInternal(const int ID, const ImU32* keys, const int count); + +// Returns line style data for a given line style. Do not store the returned value between frames as it may be invalidated if texture atlas is rebuilt. IMPLOT_API const ImPlotLineStyleData& GetLineStyleData(ImPlotLineStyle style); //-----------------------------------------------------------------------------