diff --git a/implot.cpp b/implot.cpp index 643f904..134184a 100644 --- a/implot.cpp +++ b/implot.cpp @@ -48,21 +48,16 @@ You can read releases logs https://github.com/epezent/implot/releases for more d */ -#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS) -#define _CRT_SECURE_NO_WARNINGS -#endif - -#ifdef _MSC_VER -#pragma warning (disable: 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen -#endif - #ifndef IMGUI_DEFINE_MATH_OPERATORS #define IMGUI_DEFINE_MATH_OPERATORS #endif +#include "implot.h" +#include "imgui_internal.h" -#include -#include +#ifdef _MSC_VER +#define sprintf sprintf_s +#endif #define IM_NORMALIZE2F_OVER_ZERO(VX, VY) \ { \ @@ -202,8 +197,7 @@ inline void AddTextVertical(ImDrawList *DrawList, const char *text, ImVec2 pos, pos.y = IM_ROUND(pos.y); ImFont * font = GImGui->Font; const ImFontGlyph *glyph; - char c; - while ((c = *text++)) { + for (char c = *text++; c; c = *text++) { glyph = font->FindGlyph(c); if (!glyph) continue; @@ -237,7 +231,6 @@ ImVec4 NextColor(); // Structs //----------------------------------------------------------------------------- - /// Tick mark info struct ImTick { ImTick(double value, bool major, bool render_label = true) { @@ -247,10 +240,10 @@ struct ImTick { } double PlotPos; float PixelPos; - bool Major; ImVec2 Size; - int TextOffset; - bool RenderLabel; + int TextOffset; + bool Major; + bool RenderLabel; }; struct ImPlotItem { @@ -298,13 +291,13 @@ struct ImPlotState { ImPool Items; ImRect BB_Legend; - bool Selecting; ImVec2 SelectStart; + bool Selecting; bool Querying; bool Queried; + bool DraggingQuery; ImVec2 QueryStart; ImRect QueryRect; // relative to BB_grid!! - bool DraggingQuery; ImPlotAxis XAxis; ImPlotAxis YAxis[MAX_Y_AXES]; @@ -342,9 +335,6 @@ struct ImPlotContext { ImRect BB_Frame; ImRect BB_Canvas; ImRect BB_Grid; - // Hover states - bool Hov_Frame; - bool Hov_Grid; // Cached Colors ImU32 Col_Frame, Col_Bg, Col_Border, Col_Txt, Col_TxtDis, @@ -368,14 +358,15 @@ struct ImPlotContext { // log scale denominator float LogDenX; float LogDenY[MAX_Y_AXES]; - // Data extents ImPlotRange ExtentsX; ImPlotRange ExtentsY[MAX_Y_AXES]; - - bool FitThisFrame; bool FitX; - bool FitY[MAX_Y_AXES]; int VisibleItemCount; + bool FitThisFrame; bool FitX; + bool FitY[MAX_Y_AXES] = {}; + // Hover states + bool Hov_Frame; + bool Hov_Grid; // Render flags bool RenderX, RenderY[MAX_Y_AXES]; // Mouse pos @@ -457,6 +448,11 @@ inline ImVec2 PixelsToPlot(float x, float y, int y_axis_in = -1) { return plt; } +ImVec2 PixelsToPlot(const ImVec2& pix, int y_axis) { + return PixelsToPlot(pix.x, pix.y, y_axis); +} + +// This function is convenient but should not be used to process a high volume of points. Use the Transformer structs below instead. inline ImVec2 PlotToPixels(float x, float y, int y_axis_in = -1) { IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "PlotToPixels() Needs to be called between BeginPlot() and EndPlot()!"); const int y_axis = y_axis_in >= 0 ? y_axis_in : gp.CurrentPlot->CurrentYAxis; @@ -474,14 +470,13 @@ inline ImVec2 PlotToPixels(float x, float y, int y_axis_in = -1) { return pix; } -ImVec2 PixelsToPlot(const ImVec2& pix, int y_axis) { - return PixelsToPlot(pix.x, pix.y, y_axis); -} - +// This function is convenient but should not be used to process a high volume of points. Use the Transformer structs below instead. ImVec2 PlotToPixels(const ImVec2& plt, int y_axis) { return PlotToPixels(plt.x, plt.y, y_axis); } +// Transformer structs + struct Plt2PixLinLin { Plt2PixLinLin(int y_axis_in) : y_axis(y_axis_in) {} @@ -1440,7 +1435,8 @@ class BufferWriter { private: void VWrite(const char* fmt, va_list argp) { const int written = ::vsnprintf(&Buffer[Pos], Size - Pos - 1, fmt, argp); - Pos += written; + if (written > 0) + Pos += ImMin(size_t(written), Size-Pos-1); } char* const Buffer; @@ -1599,7 +1595,10 @@ void EndPlot() { col_hl_txt = ImGui::GetColorU32(ImLerp(G.Style.Colors[ImGuiCol_Text], item->Color, 0.25f)); } else - item->Highlight = false; + { + item->Highlight = false; + col_hl_txt = gp.Col_Txt; + } ImU32 iconColor; if (hov_legend && icon_bb.Contains(IO.MousePos)) { ImVec4 colAlpha = item->Color; @@ -1615,8 +1614,7 @@ void EndPlot() { const char* label = GetLegendLabel(i); const char* text_display_end = ImGui::FindRenderedTextEnd(label, NULL); if (label != text_display_end) - DrawList.AddText(legend_content_bb.Min + legend_padding + ImVec2(legend_icon_size, i * txt_ht), - item->Show ? (item->Highlight ? col_hl_txt : gp.Col_Txt) : gp.Col_TxtDis, label, text_display_end); + DrawList.AddText(legend_content_bb.Min + legend_padding + ImVec2(legend_icon_size, i * txt_ht), item->Show ? col_hl_txt : gp.Col_TxtDis, label, text_display_end); } } @@ -1641,7 +1639,7 @@ void EndPlot() { // render mouse pos if (HasFlag(plot.Flags, ImPlotFlags_MousePos) && gp.Hov_Grid) { - static char buffer[128] = {}; + char buffer[128] = {}; BufferWriter writer(buffer, sizeof(buffer)); writer.Write("%.2f,%.2f", gp.LastMousePos[0].x, gp.LastMousePos[0].y); @@ -2002,23 +2000,23 @@ inline void MarkerRight(ImDrawList& DrawList, const ImVec2& c, float s, bool out MarkerGeneral(DrawList, marker, 3, c, s, outline, col_outline, fill, col_fill, weight); } -inline void MarkerAsterisk(ImDrawList& DrawList, const ImVec2& c, float s, bool outline, ImU32 col_outline, bool fill, ImU32 col_fill, float weight) { - ImVec2 marker[6] = {ImVec2(SQRT_3_2, 0.5f), ImVec2(0, -1), ImVec2(-SQRT_3_2, 0.5f), ImVec2(SQRT_3_2, -0.5f), ImVec2(0, 1), ImVec2(-SQRT_3_2, -0.5f)}; +inline void MarkerAsterisk(ImDrawList& DrawList, const ImVec2& c, float s, bool /*outline*/, ImU32 col_outline, bool /*fill*/, ImU32 /*col_fill*/, float weight) { + ImVec2 marker[6] = {{SQRT_3_2, 0.5f}, {0, -1}, {-SQRT_3_2, 0.5f}, {SQRT_3_2, -0.5f}, {0, 1}, {-SQRT_3_2, -0.5f}}; TransformMarker(marker, 6, c, s); DrawList.AddLine(marker[0], marker[5], col_outline, weight); DrawList.AddLine(marker[1], marker[4], col_outline, weight); DrawList.AddLine(marker[2], marker[3], col_outline, weight); } -inline void MarkerPlus(ImDrawList& DrawList, const ImVec2& c, float s, bool outline, ImU32 col_outline, bool fill, ImU32 col_fill, float weight) { - ImVec2 marker[4] = {ImVec2(1, 0), ImVec2(0, -1), ImVec2(-1, 0), ImVec2(0, 1)}; +inline void MarkerPlus(ImDrawList& DrawList, const ImVec2& c, float s, bool /*outline*/, ImU32 col_outline, bool /*fill*/, ImU32 /*col_fill*/, float weight) { + ImVec2 marker[4] = {{1, 0}, {0, -1}, {-1, 0}, {0, 1}}; TransformMarker(marker, 4, c, s); DrawList.AddLine(marker[0], marker[2], col_outline, weight); DrawList.AddLine(marker[1], marker[3], col_outline, weight); } -inline void MarkerCross(ImDrawList& DrawList, const ImVec2& c, float s, bool outline, ImU32 col_outline, bool fill, ImU32 col_fill, float weight) { - ImVec2 marker[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)}; +inline void MarkerCross(ImDrawList& DrawList, const ImVec2& c, float s, bool /*outline*/, ImU32 col_outline, bool /*fill*/, ImU32 /*col_fill*/, float weight) { + ImVec2 marker[4] = {{SQRT_1_2,SQRT_1_2},{SQRT_1_2,-SQRT_1_2},{-SQRT_1_2,-SQRT_1_2},{-SQRT_1_2,SQRT_1_2}}; TransformMarker(marker, 4, c, s); DrawList.AddLine(marker[0], marker[2], col_outline, weight); DrawList.AddLine(marker[1], marker[3], col_outline, weight); @@ -2540,7 +2538,7 @@ void PieChart(const char** label_ids, float* values, int count, const ImVec2& ce DrawPieSlice(DrawList, center, radius, a0 + (a1 - a0) * 0.5f, a1, col); } if (show_percents) { - static char buffer[8]; + char buffer[8]; sprintf(buffer, "%.0f%%", percent * 100); ImVec2 size = ImGui::CalcTextSize(buffer); float angle = a0 + (a1 - a0) * 0.5f; @@ -2609,9 +2607,10 @@ inline void PlotDigitalEx(const char* label_id, Getter getter, int count, int of ImVec2 itemData1 = getter(i1); ImVec2 itemData2 = getter(i2); i1 = i2; - int pixY_0 = line_weight; - int pixY_1 = gp.Style.DigitalBitHeight * ImMax(0.0f, itemData1.y); //allow only positive values - int pixY_chPosOffset = ImMax((int)gp.Style.DigitalBitHeight, pixY_1) + gp.Style.DigitalBitGap; + int pixY_0 = (int)(line_weight); + float pixY_1_float = gp.Style.DigitalBitHeight * ImMax(0.0f, itemData1.y); + int pixY_1 = (int)(pixY_1_float); //allow only positive values + int pixY_chPosOffset = (int)(ImMax(gp.Style.DigitalBitHeight, pixY_1_float) + gp.Style.DigitalBitGap); pixYMax = ImMax(pixYMax, pixY_chPosOffset); ImVec2 pMin, pMax; pMin.x = gp.PixelRange[ax].Min.x + mx * (itemData1.x - gp.CurrentPlot->XAxis.Range.Min); @@ -2621,10 +2620,10 @@ inline void PlotDigitalEx(const char* label_id, Getter getter, int count, int of pMax.y = (gp.PixelRange[ax].Min.y) + ((-gp.DigitalPlotOffset) - pixY_0 - pixY_1 - pixY_Offset); //plot only one rectangle for same digital state while (((s+2) < segments) && (itemData1.y == itemData2.y)) { - const int i2 = (i1 + 1) % count; - itemData2 = getter(i2); + const int i3 = (i1 + 1) % count; + itemData2 = getter(i3); pMax.x = gp.PixelRange[ax].Min.x + mx * (itemData2.x - gp.CurrentPlot->XAxis.Range.Min); - i1 = i2; + i1 = i3; s++; } //do not extend plot outside plot range diff --git a/implot.h b/implot.h index 41bc707..ca22a07 100644 --- a/implot.h +++ b/implot.h @@ -23,7 +23,7 @@ // ImPlot v0.2 WIP #pragma once -#include +#include "imgui.h" //----------------------------------------------------------------------------- // Basic types and flags diff --git a/implot_demo.cpp b/implot_demo.cpp index 0e829e8..df91b18 100644 --- a/implot_demo.cpp +++ b/implot_demo.cpp @@ -22,18 +22,16 @@ // ImPlot v0.2 WIP -#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS) -#define _CRT_SECURE_NO_WARNINGS -#endif -#ifdef _MSC_VER -#pragma warning (disable: 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen -#endif - -#include +#include "implot.h" #include #include #include +#include // for 'float' overloads of elementary functions (sin,cos,etc) + +#ifdef _MSC_VER +#define sprintf sprintf_s +#endif namespace { @@ -468,11 +466,11 @@ void ShowDemoWindow(bool* p_open) { if (data.size() > 0) ImPlot::Plot("Points", &data[0].x, &data[0].y, data.size(), 0, 2 * sizeof(float)); if (ImPlot::IsPlotQueried() && data.size() > 0) { - ImPlotLimits range = ImPlot::GetPlotQuery(); + ImPlotLimits range2 = ImPlot::GetPlotQuery(); int cnt = 0; ImVec2 avg; for (int i = 0; i < data.size(); ++i) { - if (range.Contains(data[i])) { + if (range2.Contains(data[i])) { avg.x += data[i].x; avg.y += data[i].y; cnt++; @@ -659,7 +657,7 @@ void ShowDemoWindow(bool* p_open) { dataDigital[i].AddPoint(t, sin(2*t) < 0.45); i++; if (showDigital[i]) - dataDigital[i].AddPoint(t, (int)t % 5); + dataDigital[i].AddPoint(t, fmod(t,5.0f)); i++; if (showDigital[i]) dataDigital[i].AddPoint(t, sin(2*t) < 0.17); @@ -701,13 +699,18 @@ void ShowDemoWindow(bool* p_open) { ImPlot::EndPlot(); } if (ImGui::BeginDragDropTarget()) { - if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("DND_DIGITAL_PLOT")) { + const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("DND_DIGITAL_PLOT"); + if (payload) { int i = *(int*)payload->Data; showDigital[i] = true; } - else if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("DND_ANALOG_PLOT")) { - int i = *(int*)payload->Data; - showAnalog[i] = true; + else + { + payload = ImGui::AcceptDragDropPayload("DND_ANALOG_PLOT"); + if (payload) { + int i = *(int*)payload->Data; + showAnalog[i] = true; + } } ImGui::EndDragDropTarget(); }