diff --git a/implot.cpp b/implot.cpp index 9a5ce87..310979c 100644 --- a/implot.cpp +++ b/implot.cpp @@ -106,7 +106,7 @@ ImPlotStyle::ImPlotStyle() { DigitalBitHeight = 8; DigitalBitGap = 4; AntiAliasedLines = false; - + PlotBorderSize = 1; MinorAlpha = 0.25f; MajorTickLen = ImVec2(10,10); @@ -333,8 +333,9 @@ void Reset(ImPlotContext* ctx) { if (ctx->ChildWindowMade) ImGui::EndChild(); ctx->ChildWindowMade = false; - // reset the next plot data + // reset the next plot/item data ctx->NextPlotData = ImPlotNextPlotData(); + ctx->NextItemStyle = ImPlotItemStyle(); // reset items count ctx->VisibleItemCount = 0; // reset legend items @@ -360,6 +361,7 @@ void Reset(ImPlotContext* ctx) { ctx->DigitalPlotOffset = 0; // nullify plot ctx->CurrentPlot = NULL; + ctx->CurrentItem = NULL; } //----------------------------------------------------------------------------- @@ -409,13 +411,11 @@ void UpdateTransformCache() { ImHasFlag(gp.CurrentPlot->YAxis[i].Flags, ImPlotAxisFlags_Invert) ? gp.BB_Plot.Min.y : gp.BB_Plot.Max.y, ImHasFlag(gp.CurrentPlot->XAxis.Flags, ImPlotAxisFlags_Invert) ? gp.BB_Plot.Min.x : gp.BB_Plot.Max.x, ImHasFlag(gp.CurrentPlot->YAxis[i].Flags, ImPlotAxisFlags_Invert) ? gp.BB_Plot.Max.y : gp.BB_Plot.Min.y); - gp.My[i] = (gp.PixelRange[i].Max.y - gp.PixelRange[i].Min.y) / gp.CurrentPlot->YAxis[i].Range.Size(); } gp.LogDenX = ImLog10(gp.CurrentPlot->XAxis.Range.Max / gp.CurrentPlot->XAxis.Range.Min); - for (int i = 0; i < IMPLOT_Y_AXES; i++) { + for (int i = 0; i < IMPLOT_Y_AXES; i++) gp.LogDenY[i] = ImLog10(gp.CurrentPlot->YAxis[i].Range.Max / gp.CurrentPlot->YAxis[i].Range.Min); - } gp.Mx = (gp.PixelRange[0].Max.x - gp.PixelRange[0].Min.x) / gp.CurrentPlot->XAxis.Range.Size(); } @@ -465,61 +465,6 @@ ImVec2 PlotToPixels(const ImPlotPoint& plt, int y_axis) { return PlotToPixels(plt.x, plt.y, y_axis); } -//----------------------------------------------------------------------------- -// Item Utils -//----------------------------------------------------------------------------- - -ImPlotItem* RegisterOrGetItem(const char* label_id) { - ImPlotContext& gp = *GImPlot; - ImGuiID id = ImGui::GetID(label_id); - ImPlotItem* item = gp.CurrentPlot->Items.GetOrAddByKey(id); - if (item->SeenThisFrame) - return item; - item->SeenThisFrame = true; - int idx = gp.CurrentPlot->Items.GetIndex(item); - item->ID = id; - if (ImGui::FindRenderedTextEnd(label_id, NULL) != label_id) { - gp.LegendIndices.push_back(idx); - item->NameOffset = gp.LegendLabels.size(); - gp.LegendLabels.append(label_id, label_id + strlen(label_id) + 1); - } - else { - item->Show = true; - } - if (item->Show) - gp.VisibleItemCount++; - return item; -} - -ImPlotItem* GetItem(int i) { - ImPlotContext& gp = *GImPlot; - return gp.CurrentPlot->Items.GetByIndex(gp.LegendIndices[i]); -} - -ImPlotItem* GetItem(const char* label_id) { - ImPlotContext& gp = *GImPlot; - ImGuiID id = ImGui::GetID(label_id); - return gp.CurrentPlot->Items.GetByKey(id); -} - -ImPlotItem* GetItem(const char* plot_title, const char* item_label_id) { - ImPlotState* plot = GetPlot(plot_title); - if (plot) { - ImGuiID id = ImGui::GetID(item_label_id); - return plot->Items.GetByKey(id); - } - return NULL; -} - -void BustItemCache() { - ImPlotContext& gp = *GImPlot; - for (int p = 0; p < gp.Plots.GetSize(); ++p) { - ImPlotState& plot = *gp.Plots.GetByIndex(p); - plot.ColormapIdx = 0; - plot.Items.Clear(); - } -} - //----------------------------------------------------------------------------- // Legend Utils //----------------------------------------------------------------------------- @@ -566,12 +511,12 @@ void AddTicksDefault(const ImPlotRange& range, int nMajor, int nMinor, ImPlotTic const double graphmin = floor(range.Min / interval) * interval; const double graphmax = ceil(range.Max / interval) * interval; for (double major = graphmin; major < graphmax + 0.5 * interval; major += interval) { - if (range.Contains(major)) + if (range.Contains(major)) ticks.AddTick(major, true, true, LabelTickDefault); for (int i = 1; i < nMinor; ++i) { double minor = major + i * interval / nMinor; - if (range.Contains(minor)) - ticks.AddTick(minor, false, true, LabelTickDefault); + if (range.Contains(minor)) + ticks.AddTick(minor, false, true, LabelTickDefault); } } } @@ -592,17 +537,17 @@ void AddTicksLogarithmic(const ImPlotRange& range, int nMajor, ImPlotTickCollect double major1 = ImPow(10, (double)(e)); double major2 = ImPow(10, (double)(e + 1)); double interval = (major2 - major1) / 9; - if (major1 >= (range.Min - DBL_EPSILON) && major1 <= (range.Max + DBL_EPSILON)) - ticks.AddTick(major1, true, true, LabelTickScientific); + if (major1 >= (range.Min - DBL_EPSILON) && major1 <= (range.Max + DBL_EPSILON)) + ticks.AddTick(major1, true, true, LabelTickScientific); for (int j = 0; j < exp_step; ++j) { major1 = ImPow(10, (double)(e+j)); major2 = ImPow(10, (double)(e+j+1)); interval = (major2 - major1) / 9; for (int i = 1; i < (9 + (int)(j < (exp_step - 1))); ++i) { double minor = major1 + i * interval; - if (minor >= (range.Min - DBL_EPSILON) && minor <= (range.Max + DBL_EPSILON)) - ticks.AddTick(minor, false, false, LabelTickScientific); - + if (minor >= (range.Min - DBL_EPSILON) && minor <= (range.Max + DBL_EPSILON)) + ticks.AddTick(minor, false, false, LabelTickScientific); + } } } @@ -740,10 +685,21 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons gp.LockPlot = gp.X.Lock && gp.Y[0].Lock && gp.Y[1].Lock && gp.Y[2].Lock; + for (int i = 0; i < IMPLOT_Y_AXES; ++i) { + if (!ImHasFlag(plot.XAxis.Flags, ImPlotAxisFlags_LogScale) && !ImHasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_LogScale)) + gp.Scales[i] = ImPlotScale_LinLin; + else if (ImHasFlag(plot.XAxis.Flags, ImPlotAxisFlags_LogScale) && !ImHasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_LogScale)) + gp.Scales[i] = ImPlotScale_LogLin; + else if (!ImHasFlag(plot.XAxis.Flags, ImPlotAxisFlags_LogScale) && ImHasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_LogScale)) + gp.Scales[i] = ImPlotScale_LinLog; + else if (ImHasFlag(plot.XAxis.Flags, ImPlotAxisFlags_LogScale) && ImHasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_LogScale)) + gp.Scales[i] = ImPlotScale_LogLog; + } + // CONSTRAINTS ------------------------------------------------------------ ConstrainAxis(plot.XAxis); - for (int i = 0; i < IMPLOT_Y_AXES; i++) + for (int i = 0; i < IMPLOT_Y_AXES; i++) ConstrainAxis(plot.YAxis[i]); // AXIS COLORS ----------------------------------------------------------------- @@ -1528,15 +1484,17 @@ void EndPlot() { col_hl_txt = ImGui::GetColorU32(col_txt); } ImU32 iconColor; + ImVec4 item_color = item->Color; + item_color.w = 1; if (hov_legend && icon_bb.Contains(IO.MousePos)) { - ImVec4 colAlpha = item->Color; + ImVec4 colAlpha = item_color; colAlpha.w = 0.5f; iconColor = item->Show ? ImGui::GetColorU32(colAlpha) : ImGui::GetColorU32(ImGuiCol_TextDisabled, 0.5f); if (IO.MouseClicked[0]) item->Show = !item->Show; } else { - iconColor = item->Show ? ImGui::GetColorU32(item->Color) : col_txt_dis; + iconColor = item->Show ? ImGui::GetColorU32(item_color) : col_txt_dis; } DrawList.AddRectFilled(icon_bb.Min, icon_bb.Max, iconColor, 1); const char* label = GetLegendLabel(i); @@ -1776,6 +1734,10 @@ ImVec2 GetPlotSize() { return gp.BB_Plot.GetSize(); } +ImDrawList* GetPlotDrawList() { + return ImGui::GetWindowDrawList(); +} + void PushPlotClipRect() { ImPlotContext& gp = *GImPlot; IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "PushPlotClipRect() needs to be called between BeginPlot() and EndPlot()!"); @@ -2215,7 +2177,7 @@ void ShowColormapScale(double scale_min, double scale_max, float height) { ImPlotRange range; range.Min = scale_min; range.Max = scale_max; - + AddTicksDefault(range, 10, 0, ticks); @@ -2232,7 +2194,7 @@ void ShowColormapScale(double scale_min, double scale_max, float height) { ImGui::ItemSize(bb_frame); if (!ImGui::ItemAdd(bb_frame, 0, &bb_frame)) return; - ImGui::RenderFrame(bb_frame.Min, bb_frame.Max, ImGui::GetColorU32(ImGuiCol_FrameBg)); + ImGui::RenderFrame(bb_frame.Min, bb_frame.Max, GetStyleColorU32(ImPlotCol_FrameBg)); ImRect bb_grad(bb_frame.Min + gp.Style.PlotPadding, bb_frame.Min + ImVec2(bar_w + gp.Style.PlotPadding.x, height - gp.Style.PlotPadding.y)); int num_cols = GetColormapSize(); @@ -2243,18 +2205,20 @@ void ShowColormapScale(double scale_min, double scale_max, float height) { ImU32 col2 = ImGui::GetColorU32(GetColormapColor(num_cols - 1 - (i+1))); DrawList.AddRectFilledMultiColor(rect.Min, rect.Max, col1, col1, col2, col2); } - ImU32 col_border = gp.Style.Colors[ImPlotCol_PlotBorder].w == -1 ? ImGui::GetColorU32(ImGuiCol_Text, 0.5f) : ImGui::GetColorU32(gp.Style.Colors[ImPlotCol_PlotBorder]); + ImVec4 col_tik4 = ImGui::GetStyleColorVec4(ImGuiCol_Text); + col_tik4.w *= 0.25f; + const ImU32 col_tick = ImGui::GetColorU32(col_tik4); ImGui::PushClipRect(bb_frame.Min, bb_frame.Max, true); for (int i = 0; i < ticks.Size; ++i) { float ypos = ImRemap((float)ticks.Ticks[i].PlotPos, (float)range.Max, (float)range.Min, bb_grad.Min.y, bb_grad.Max.y); if (ypos < bb_grad.Max.y - 2 && ypos > bb_grad.Min.y + 2) - DrawList.AddLine(ImVec2(bb_grad.Max.x-1, ypos), ImVec2(bb_grad.Max.x - (ticks.Ticks[i].Major ? 10.0f : 5.0f), ypos), col_border, 1.0f); - DrawList.AddText(ImVec2(bb_grad.Max.x-1, ypos) + ImVec2(txt_off, -ticks.Ticks[i].LabelSize.y * 0.5f), ImGui::GetColorU32(ImGuiCol_Text), ticks.GetLabel(i)); + DrawList.AddLine(ImVec2(bb_grad.Max.x-1, ypos), ImVec2(bb_grad.Max.x - (ticks.Ticks[i].Major ? 10.0f : 5.0f), ypos), col_tick, 1.0f); + DrawList.AddText(ImVec2(bb_grad.Max.x-1, ypos) + ImVec2(txt_off, -ticks.Ticks[i].LabelSize.y * 0.5f), GetStyleColorU32(ImPlotCol_TitleText), ticks.GetLabel(i)); } ImGui::PopClipRect(); - DrawList.AddRect(bb_grad.Min, bb_grad.Max, col_border); + DrawList.AddRect(bb_grad.Min, bb_grad.Max, GetStyleColorU32(ImPlotCol_PlotBorder)); } @@ -2361,7 +2325,7 @@ void ShowStyleEditor(ImPlotStyle* ref) { const char* name = ImPlot::GetStyleColorName(i); if (!output_only_modified || memcmp(&col, &ref->Colors[i], sizeof(ImVec4)) != 0) { if (IsColorAuto(i)) - ImGui::LogText("colors[ImPlotCol_%s]%*s= IMPLOT_COL_AUTO;\n",name,14 - (int)strlen(name), ""); + ImGui::LogText("colors[ImPlotCol_%s]%*s= IMPLOT_AUTO_COL;\n",name,14 - (int)strlen(name), ""); else ImGui::LogText("colors[ImPlotCol_%s]%*s= ImVec4(%.2ff, %.2ff, %.2ff, %.2ff);\n", name, 14 - (int)strlen(name), "", col.x, col.y, col.z, col.w); @@ -2398,7 +2362,7 @@ void ShowStyleEditor(ImPlotStyle* ref) { if (is_auto) style.Colors[i] = temp; else - style.Colors[i] = IMPLOT_COL_AUTO; + style.Colors[i] = IMPLOT_AUTO_COL; BustItemCache(); } if (!is_auto) @@ -2419,7 +2383,7 @@ void ShowStyleEditor(ImPlotStyle* ref) { } ImGui::PopItemWidth(); ImGui::Separator(); - ImGui::Text("Colors that are set to Auto (i.e. IMPLOT_COL_AUTO) will\n" + 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."); @@ -2551,31 +2515,31 @@ void StyleColorsAuto(ImPlotStyle* dst) { style->MinorAlpha = 0.25f; - colors[ImPlotCol_Line] = IMPLOT_COL_AUTO; - colors[ImPlotCol_Fill] = IMPLOT_COL_AUTO; - colors[ImPlotCol_MarkerOutline] = IMPLOT_COL_AUTO; - colors[ImPlotCol_MarkerFill] = IMPLOT_COL_AUTO; - colors[ImPlotCol_ErrorBar] = IMPLOT_COL_AUTO; - colors[ImPlotCol_FrameBg] = IMPLOT_COL_AUTO; - colors[ImPlotCol_PlotBg] = IMPLOT_COL_AUTO; - colors[ImPlotCol_PlotBorder] = IMPLOT_COL_AUTO; - colors[ImPlotCol_LegendBg] = IMPLOT_COL_AUTO; - colors[ImPlotCol_LegendBorder] = IMPLOT_COL_AUTO; - colors[ImPlotCol_LegendText] = IMPLOT_COL_AUTO; - colors[ImPlotCol_TitleText] = IMPLOT_COL_AUTO; - colors[ImPlotCol_InlayText] = IMPLOT_COL_AUTO; - colors[ImPlotCol_PlotBorder] = IMPLOT_COL_AUTO; - colors[ImPlotCol_XAxis] = IMPLOT_COL_AUTO; - colors[ImPlotCol_XAxisGrid] = IMPLOT_COL_AUTO; - colors[ImPlotCol_YAxis] = IMPLOT_COL_AUTO; - colors[ImPlotCol_YAxisGrid] = IMPLOT_COL_AUTO; - colors[ImPlotCol_YAxis2] = IMPLOT_COL_AUTO; - colors[ImPlotCol_YAxisGrid2] = IMPLOT_COL_AUTO; - colors[ImPlotCol_YAxis3] = IMPLOT_COL_AUTO; - colors[ImPlotCol_YAxisGrid3] = IMPLOT_COL_AUTO; - colors[ImPlotCol_Selection] = IMPLOT_COL_AUTO; - colors[ImPlotCol_Query] = IMPLOT_COL_AUTO; - colors[ImPlotCol_Crosshairs] = IMPLOT_COL_AUTO; + 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; + colors[ImPlotCol_LegendBg] = IMPLOT_AUTO_COL; + colors[ImPlotCol_LegendBorder] = IMPLOT_AUTO_COL; + colors[ImPlotCol_LegendText] = IMPLOT_AUTO_COL; + colors[ImPlotCol_TitleText] = IMPLOT_AUTO_COL; + colors[ImPlotCol_InlayText] = IMPLOT_AUTO_COL; + colors[ImPlotCol_PlotBorder] = IMPLOT_AUTO_COL; + colors[ImPlotCol_XAxis] = IMPLOT_AUTO_COL; + colors[ImPlotCol_XAxisGrid] = IMPLOT_AUTO_COL; + colors[ImPlotCol_YAxis] = IMPLOT_AUTO_COL; + colors[ImPlotCol_YAxisGrid] = IMPLOT_AUTO_COL; + colors[ImPlotCol_YAxis2] = IMPLOT_AUTO_COL; + colors[ImPlotCol_YAxisGrid2] = IMPLOT_AUTO_COL; + colors[ImPlotCol_YAxis3] = IMPLOT_AUTO_COL; + colors[ImPlotCol_YAxisGrid3] = IMPLOT_AUTO_COL; + colors[ImPlotCol_Selection] = IMPLOT_AUTO_COL; + colors[ImPlotCol_Query] = IMPLOT_AUTO_COL; + colors[ImPlotCol_Crosshairs] = IMPLOT_AUTO_COL; } void StyleColorsClassic(ImPlotStyle* dst) { @@ -2584,10 +2548,10 @@ void StyleColorsClassic(ImPlotStyle* dst) { style->MinorAlpha = 0.5f; - colors[ImPlotCol_Line] = IMPLOT_COL_AUTO; - colors[ImPlotCol_Fill] = IMPLOT_COL_AUTO; - colors[ImPlotCol_MarkerOutline] = IMPLOT_COL_AUTO; - colors[ImPlotCol_MarkerFill] = IMPLOT_COL_AUTO; + 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); @@ -2616,11 +2580,11 @@ void StyleColorsDark(ImPlotStyle* dst) { style->MinorAlpha = 0.25f; - colors[ImPlotCol_Line] = IMPLOT_COL_AUTO; - colors[ImPlotCol_Fill] = IMPLOT_COL_AUTO; - colors[ImPlotCol_MarkerOutline] = IMPLOT_COL_AUTO; - colors[ImPlotCol_MarkerFill] = IMPLOT_COL_AUTO; - colors[ImPlotCol_ErrorBar] = IMPLOT_COL_AUTO; + 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); @@ -2648,11 +2612,11 @@ void StyleColorsLight(ImPlotStyle* dst) { style->MinorAlpha = 1.0f; - colors[ImPlotCol_Line] = IMPLOT_COL_AUTO; - colors[ImPlotCol_Fill] = IMPLOT_COL_AUTO; - colors[ImPlotCol_MarkerOutline] = IMPLOT_COL_AUTO; - colors[ImPlotCol_MarkerFill] = IMPLOT_COL_AUTO; - colors[ImPlotCol_ErrorBar] = IMPLOT_COL_AUTO; + 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 378b45c..1c93bc0 100644 --- a/implot.h +++ b/implot.h @@ -25,7 +25,16 @@ #pragma once #include "imgui.h" +//----------------------------------------------------------------------------- +// Macros and Defines +//----------------------------------------------------------------------------- + +// ImPlot version string #define IMPLOT_VERSION "0.5 WIP" +// 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) //----------------------------------------------------------------------------- // Forward Declarations and Basic Types @@ -73,13 +82,13 @@ enum ImPlotAxisFlags_ { // Plot styling colors. enum ImPlotCol_ { - // item related colors + // 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 related colors + // 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) @@ -133,7 +142,7 @@ enum ImPlotStyleVar_ { // Marker specifications. enum ImPlotMarker_ { - ImPlotMarker_None, // no marker + ImPlotMarker_None = -1, // no marker ImPlotMarker_Circle, // a circle marker ImPlotMarker_Square, // a square maker ImPlotMarker_Diamond, // a diamond marker @@ -204,8 +213,8 @@ struct ImPlotStyle { 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 - bool AntiAliasedLines; // = false, enable global anti-aliasing on plot lines (overrides ImPlotFlags_AntiAliased) // plot styling variables + bool AntiAliasedLines; // = false, enable global anti-aliasing on plot lines (overrides ImPlotFlags_AntiAliased) 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 @@ -266,8 +275,8 @@ void SetCurrentContext(ImPlotContext* ctx); // Starts a 2D plotting context. If this function returns true, EndPlot() must // be called, e.g. "if (BeginPlot(...)) { ... EndPlot(); }". #title_id must // be unique. If you need to avoid ID collisions or don't want to display a -// title in the plot, use double hashes (e.g. "MyPlot##Hidden"). If #x_label -// and/or #y_label are provided, axes labels will be displayed. +// title in the plot, use double hashes (e.g. "MyPlot##Hidden" or "##NoTitle"). +// If #x_label and/or #y_label are provided, axes labels will be displayed. bool BeginPlot(const char* title_id, const char* x_label = NULL, const char* y_label = NULL, @@ -381,17 +390,20 @@ void SetNextPlotTicksY(double y_min, double y_max, int n_ticks, const char** lab void SetPlotYAxis(int y_axis); // Convert pixels to a position in the current plot's coordinate system. A negative y_axis uses the current value of SetPlotYAxis (0 initially). -ImPlotPoint PixelsToPlot(const ImVec2& pix, int y_axis = -1); -ImPlotPoint PixelsToPlot(float x, float y, int y_axis = -1); +ImPlotPoint PixelsToPlot(const ImVec2& pix, int y_axis = IMPLOT_AUTO); +ImPlotPoint PixelsToPlot(float x, float y, int y_axis = IMPLOT_AUTO); // Convert a position in the current plot's coordinate system to pixels. A negative y_axis uses the current value of SetPlotYAxis (0 initially). -ImVec2 PlotToPixels(const ImPlotPoint& plt, int y_axis = -1); -ImVec2 PlotToPixels(double x, double y, int y_axis = -1); +ImVec2 PlotToPixels(const ImPlotPoint& plt, int y_axis = IMPLOT_AUTO); +ImVec2 PlotToPixels(double x, double y, int y_axis = IMPLOT_AUTO); //----------------------------------------------------------------------------- // Plot Queries //----------------------------------------------------------------------------- +// Use these functions to retrieve information about the current plot. They +// MUST be called between BeginPlot and EndPlot! + // Get the current Plot position (top-left) in pixels. ImVec2 GetPlotPos(); // Get the curent Plot size in pixels. @@ -403,18 +415,18 @@ bool IsPlotXAxisHovered(); // Returns true if the YAxis[n] plot area in the current plot is hovered. bool IsPlotYAxisHovered(int y_axis = 0); // Returns the mouse position in x,y coordinates of the current plot. A negative y_axis uses the current value of SetPlotYAxis (0 initially). -ImPlotPoint GetPlotMousePos(int y_axis = -1); +ImPlotPoint GetPlotMousePos(int y_axis = IMPLOT_AUTO); // Returns the current plot axis range. A negative y_axis uses the current value of SetPlotYAxis (0 initially). -ImPlotLimits GetPlotLimits(int y_axis = -1); +ImPlotLimits GetPlotLimits(int y_axis = IMPLOT_AUTO); // Returns true if the current plot is being queried. bool IsPlotQueried(); // Returns the current plot query bounds. -ImPlotLimits GetPlotQuery(int y_axis = -1); +ImPlotLimits GetPlotQuery(int y_axis = IMPLOT_AUTO); // Returns true if a plot item legend entry is hovered. bool IsLegendEntryHovered(const char* label_id); //----------------------------------------------------------------------------- -// Plot and Item Styling and Colormaps +// Plot and Item Styling //----------------------------------------------------------------------------- // Provides access to plot style structure for permanant modifications to colors, sizes, etc. @@ -429,14 +441,14 @@ void StyleColorsDark(ImPlotStyle* dst = NULL); // Style colors for ImGui "Light". void StyleColorsLight(ImPlotStyle* dst = NULL); -// Special color used to indicate that a style color should be deduced automatically from ImGui style or ImPlot colormaps. -#define IMPLOT_COL_AUTO ImVec4(0,0,0,-1) +// Use PushStyleX to temporarily modify your ImPlotStyle. The modification +// will last until the matching call to PopStyleX. You MUST call a pop for +// every push, otherwise you will leak memory! This behaves just like ImGui. // Temporarily modify a plot color. Don't forget to call PopStyleColor! void PushStyleColor(ImPlotCol idx, ImU32 col); -// Temporarily modify a plot color. Don't forget to call PopStyleColor! void PushStyleColor(ImPlotCol idx, const ImVec4& col); -// Undo temporary color modification. +// Undo temporary color modification. Undo multiple pushes at once by increasing count. void PopStyleColor(int count = 1); // Temporarily modify a style variable of float type. Don't forget to call PopStyleVar! @@ -445,9 +457,39 @@ void PushStyleVar(ImPlotStyleVar idx, float val); void PushStyleVar(ImPlotStyleVar idx, int val); // Temporarily modify a style variable of ImVec2 type. Don't forget to call PopStyleVar! void PushStyleVar(ImPlotStyleVar idx, const ImVec2& val); -// Undo temporary style modification. +// Undo temporary style modification. Undo multiple pushes at once by increasing count. 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 the your ImPlotStyle or from Colormap data. + +// Set the line color and weight for the next item only. +void SetNextLineStyle(const ImVec4& col = IMPLOT_AUTO_COL, float weight = IMPLOT_AUTO); +// Set the fill color for the next item only. +void SetNextFillStyle(const ImVec4& col = IMPLOT_AUTO_COL, float alpha_mod = IMPLOT_AUTO); +// Set the marker style for the next item only. +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. +void SetNextErrorBarStyle(const ImVec4& col = IMPLOT_AUTO_COL, float size = IMPLOT_AUTO, float weight = IMPLOT_AUTO); + +// Returns the null terminated string name for an ImPlotCol. +const char* GetStyleColorName(ImPlotCol color); + +//----------------------------------------------------------------------------- +// Colormaps +//----------------------------------------------------------------------------- + +// Item styling is based on Colormaps when the relevant ImPlotCol is set to +// IMPLOT_AUTO_COL (default). Several built in colormaps are available and can be +// toggled in the demo. You can push/pop or set your own colormaps as well. + +// The Colormap data will be ignored and a custom color will be used if you have either: +// 1) Modified an item style color in your ImPlotStyle to anything but IMPLOT_AUTO_COL. +// 2) Pushed an item style color using PushStyleColor(). +// 3) Set the next item style with a SetNextXStyle function. + // Temporarily switch to one of the built-in colormaps. void PushColormap(ImPlotColormap colormap); // Temporarily switch to your custom colormap. The pointer data must persist until the matching call to PopColormap! @@ -458,22 +500,18 @@ void PopColormap(int count = 1); void SetColormap(const ImVec4* colormap, int size); // Permanently switch to one of the built-in colormaps. If samples is greater than 1, the map will be linearly resampled. Don't call this each frame. void SetColormap(ImPlotColormap colormap, int samples = 0); - // Returns the size of the current colormap. int GetColormapSize(); -// Returns a color from the Color map given an index >= 0 (modulo will be performed) +// Returns a color from the Color map given an index >= 0 (modulo will be performed). ImVec4 GetColormapColor(int index); // Linearly interpolates a color from the current colormap given t between 0 and 1. ImVec4 LerpColormap(float t); // Returns the next unused colormap color and advances the colormap. Can be used to skip colors if desired. ImVec4 NextColormapColor(); - -const char* GetStyleColorName(ImPlotCol color); -// Returns a null terminated string name for a built-in colormap -const char* GetColormapName(ImPlotColormap colormap); - -// Renders a vertical color scale using the current color map. +// Renders a vertical color scale using the current color map. Call this outside of Begin/EndPlot. void ShowColormapScale(double scale_min, double scale_max, float height); +// Returns a null terminated string name for a built-in colormap. +const char* GetColormapName(ImPlotColormap colormap); //----------------------------------------------------------------------------- // Miscellaneous @@ -489,6 +527,8 @@ void ShowStyleEditor(ImPlotStyle* ref = NULL); // Add basic help/info block (not a window): how to manipulate ImPlot as an end-user. void ShowUserGuide(); +// Get the plot draw list for rendering to the current plot area. +ImDrawList* GetPlotDrawList(); // Push clip rect for rendering to current plot area. void PushPlotClipRect(); // Pop plot clip rect. diff --git a/implot_demo.cpp b/implot_demo.cpp index a92a5f3..955d822 100644 --- a/implot_demo.cpp +++ b/implot_demo.cpp @@ -181,7 +181,7 @@ void ShowDemoWindow(bool* p_open) { ImGui::BulletText("Software AA can be enabled globally with ImPlotStyle.AntiAliasedLines."); ImGui::BulletText("Software AA can be enabled per plot with ImPlotFlags_AntiAliased."); ImGui::BulletText("AA for plots can be toggled from the plot's context menu."); - ImGui::BulletText("If permitable, you are better off using hardware AA (e.g. MSAA)."); + ImGui::BulletText("If permitable, you are better off using hardware AA (e.g. MSAA)."); ImGui::Unindent(); ImGui::BulletText("If you see visual artifacts, do one of the following:"); ImGui::Indent(); @@ -236,16 +236,11 @@ void ShowDemoWindow(bool* p_open) { xs2[i] = i * 0.1f; ys2[i] = xs2[i] * xs2[i]; } - static float weight = ImPlot::GetStyle().LineWeight; ImGui::BulletText("Anti-aliasing can be enabled from the plot's context menu (see Help)."); - ImGui::DragFloat("Line Weight", &weight, 0.05f, 1.0f, 5.0f, "%.2f px"); - if (ImPlot::BeginPlot("Line Plot", "x", "f(x)")) { - ImPlot::PushStyleVar(ImPlotStyleVar_LineWeight, weight); ImPlot::PlotLine("sin(x)", xs1, ys1, 1001); - ImPlot::PushStyleVar(ImPlotStyleVar_Marker, ImPlotMarker_Circle); + ImPlot::SetNextMarkerStyle(ImPlotMarker_Circle); ImPlot::PlotLine("x^2", xs2, ys2, 11); - ImPlot::PopStyleVar(2); ImPlot::EndPlot(); } } @@ -325,11 +320,10 @@ void ShowDemoWindow(bool* p_open) { if (ImPlot::BeginPlot("Scatter Plot", NULL, NULL)) { ImPlot::PlotScatter("Data 1", xs1, ys1, 100); - ImPlot::PushStyleVar(ImPlotStyleVar_MarkerSize, 6); - ImPlot::PushStyleVar(ImPlotStyleVar_Marker, ImPlotMarker_Square); ImPlot::PushStyleVar(ImPlotStyleVar_FillAlpha, 0.25f); + ImPlot::SetNextMarkerStyle(ImPlotMarker_Square, 6, ImVec4(0,1,0,0.5f), IMPLOT_AUTO, ImVec4(0,1,0,1)); ImPlot::PlotScatter("Data 2", xs2, ys2, 50); - ImPlot::PopStyleVar(3); + ImPlot::PopStyleVar(); ImPlot::EndPlot(); } } @@ -351,19 +345,19 @@ void ShowDemoWindow(bool* p_open) { ImPlot::SetNextPlotLimits(-0.5, 9.5, 0, 110, ImGuiCond_Always); ImPlot::SetNextPlotTicksX(positions, 10, labels); } - if (ImPlot::BeginPlot("Bar Plot", horz ? "Score": "Student", horz ? "Student" : "Score", + if (ImPlot::BeginPlot("Bar Plot", horz ? "Score" : "Student", horz ? "Student" : "Score", ImVec2(-1,0), ImPlotFlags_Default, ImPlotAxisFlags_Default, horz ? ImPlotAxisFlags_Default | ImPlotAxisFlags_Invert : ImPlotAxisFlags_Default)) { if (horz) { ImPlot::PlotBarsH("Midterm Exam", midtm, 10, 0.2f, -0.2f); - ImPlot::PlotBarsH("Final Exam", final, 10, 0.2f, 0); - ImPlot::PlotBarsH("Course Grade", grade, 10, 0.2f, 0.2f); + ImPlot::PlotBarsH("Final Exam", final, 10, 0.2f, 0); + ImPlot::PlotBarsH("Course Grade", grade, 10, 0.2f, 0.2f); } else { ImPlot::PlotBars("Midterm Exam", midtm, 10, 0.2f, -0.2f); - ImPlot::PlotBars("Final Exam", final, 10, 0.2f, 0); - ImPlot::PlotBars("Course Grade", grade, 10, 0.2f, 0.2f); + ImPlot::PlotBars("Final Exam", final, 10, 0.2f, 0); + ImPlot::PlotBars("Course Grade", grade, 10, 0.2f, 0.2f); } ImPlot::EndPlot(); } @@ -378,29 +372,25 @@ void ShowDemoWindow(bool* p_open) { static t_float err2[5] = {0.4f, 0.2f, 0.4f, 0.8f, 0.6f}; static t_float err3[5] = {0.09f, 0.14f, 0.09f, 0.12f, 0.16f}; static t_float err4[5] = {0.02f, 0.08f, 0.15f, 0.05f, 0.2f}; - static float size = ImPlot::GetStyle().ErrorBarSize; - static float weight = ImPlot::GetStyle().ErrorBarWeight; - ImGui::DragFloat("Error Bar Size", &size, 0.1f, 0, 10,"%.2f px"); - ImGui::DragFloat("Error Bar Weight",&weight,0.01f,1,3,"%.2f px"); + ImPlot::SetNextPlotLimits(0, 6, 0, 10); if (ImPlot::BeginPlot("##ErrorBars",NULL,NULL)) { - ImPlot::PushStyleVar(ImPlotStyleVar_ErrorBarSize, size); - ImPlot::PushStyleVar(ImPlotStyleVar_ErrorBarWeight, weight); + ImPlot::PlotBars("Bar", xs, bar, 5, 0.5f); - // error bars can be grouped with the associated item by using the same label ID ImPlot::PlotErrorBars("Bar", xs, bar, err1, 5); - ImPlot::PushStyleVar(ImPlotStyleVar_Marker, ImPlotMarker_Circle); - ImPlot::PushStyleColor(ImPlotCol_ErrorBar, ImPlot::GetColormapColor(1)); + + ImPlot::SetNextErrorBarStyle(ImPlot::GetColormapColor(1), 0); ImPlot::PlotErrorBars("Line", xs, lin1, err1, err2, 5); + ImPlot::SetNextMarkerStyle(ImPlotMarker_Circle); ImPlot::PlotLine("Line", xs, lin1, 5); - ImPlot::PushStyleVar(ImPlotStyleVar_Marker, ImPlotMarker_Square); + ImPlot::PushStyleColor(ImPlotCol_ErrorBar, ImPlot::GetColormapColor(2)); ImPlot::PlotErrorBars("Scatter", xs, lin2, err2, 5); ImPlot::PlotErrorBarsH("Scatter", xs, lin2, err3, err4, 5); + ImPlot::PopStyleColor(); ImPlot::PlotScatter("Scatter", xs, lin2, 5); - ImPlot::PopStyleVar(4); - ImPlot::PopStyleColor(2); + ImPlot::EndPlot(); } } @@ -465,7 +455,7 @@ void ShowDemoWindow(bool* p_open) { ImPlot::PushColormap(map); SetNextPlotTicksX(0 + 1.0/14.0, 1 - 1.0/14.0, 7, xlabels); - SetNextPlotTicksY(1- 1.0/14.0, 0 + 1.0/14.0, 7, ylabels); + SetNextPlotTicksY(1 - 1.0/14.0, 0 + 1.0/14.0, 7, ylabels); if (ImPlot::BeginPlot("##Heatmap1",NULL,NULL,ImVec2(225,225),0,axes_flags,axes_flags)) { ImPlot::PlotHeatmap("heat",values1[0],7,7,scale_min,scale_max); ImPlot::EndPlot(); @@ -517,7 +507,7 @@ void ShowDemoWindow(bool* p_open) { // two methods of plotting Data // as ImVec2* (or ImPlot*): ImPlot::PlotLine("Data 1", &rdata1.Data[0], rdata1.Data.size()); - // as float*, float* (or double*, double*) + // as float*, float* (or double*, double*) with stride of 2 * sizeof ImPlot::PlotLine("Data 2", &rdata2.Data[0].x, &rdata2.Data[0].y, rdata2.Data.size(), 0, 2 * sizeof(t_float)); ImPlot::EndPlot(); } @@ -534,37 +524,30 @@ void ShowDemoWindow(bool* p_open) { t_float xs[2] = {1,4}; t_float ys[2] = {10,11}; - ImPlot::PushStyleVar(ImPlotStyleVar_MarkerSize, mk_size); - ImPlot::PushStyleVar(ImPlotStyleVar_MarkerWeight, mk_weight); // filled markers for (int m = 1; m < ImPlotMarker_COUNT; ++m) { - ImPlot::PushStyleVar(ImPlotStyleVar_Marker, m); ImGui::PushID(m); + ImPlot::SetNextMarkerStyle(m, mk_size, IMPLOT_AUTO_COL, mk_weight); ImPlot::PlotLine("##Filled", xs, ys, 2); ImGui::PopID(); - ImPlot::PopStyleVar(); ys[0]--; ys[1]--; } xs[0] = 6; xs[1] = 9; ys[0] = 10; ys[1] = 11; // open markers - ImPlot::PushStyleColor(ImPlotCol_MarkerFill, ImVec4(0,0,0,0)); for (int m = 1; m < ImPlotMarker_COUNT; ++m) { - ImPlot::PushStyleVar(ImPlotStyleVar_Marker, m); ImGui::PushID(m); + ImPlot::SetNextMarkerStyle(m, mk_size, ImVec4(0,0,0,0), mk_weight); ImPlot::PlotLine("##Open", xs, ys, 2); ImGui::PopID(); - ImPlot::PopStyleVar(); ys[0]--; ys[1]--; } - ImPlot::PopStyleColor(); - ImPlot::PopStyleVar(2); ImPlot::PlotText("Filled Markers", 2.5f, 6.0f); ImPlot::PlotText("Open Markers", 7.5f, 6.0f); - ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1,0,1,1)); + ImPlot::PushStyleColor(ImPlotCol_InlayText, ImVec4(1,0,1,1)); ImPlot::PlotText("Vertical Text", 5.0f, 6.0f, true); - ImGui::PopStyleColor(); + ImPlot::PopStyleColor(); ImPlot::EndPlot(); } @@ -652,7 +635,6 @@ void ShowDemoWindow(bool* p_open) { ImPlotPoint pt = ImPlot::GetPlotMousePos(); data.push_back(t_float2((t_float)pt.x, (t_float)pt.y)); } - ImPlot::PushStyleVar(ImPlotStyleVar_Marker, ImPlotMarker_Diamond); if (data.size() > 0) ImPlot::PlotScatter("Points", &data[0].x, &data[0].y, data.size(), 0, 2 * sizeof(t_float)); if (ImPlot::IsPlotQueried() && data.size() > 0) { @@ -669,10 +651,10 @@ void ShowDemoWindow(bool* p_open) { if (cnt > 0) { avg.x = avg.x / cnt; avg.y = avg.y / cnt; + ImPlot::SetNextMarkerStyle(ImPlotMarker_Square); ImPlot::PlotScatter("Average", &avg.x, &avg.y, 1); } } - ImPlot::PopStyleVar(); range = ImPlot::GetPlotLimits(); query = ImPlot::GetPlotQuery(); ImPlot::EndPlot(); @@ -1045,8 +1027,8 @@ void ShowDemoWindow(bool* p_open) { ImVec2 rmin = ImPlot::PlotToPixels(ImPlotPoint(0.25f, 0.75f)); ImVec2 rmax = ImPlot::PlotToPixels(ImPlotPoint(0.75f, 0.25f)); ImPlot::PushPlotClipRect(); - ImGui::GetWindowDrawList()->AddCircleFilled(cntr,20,IM_COL32(255,255,0,255),20); - ImGui::GetWindowDrawList()->AddRect(rmin, rmax, IM_COL32(128,0,255,255)); + ImPlot::GetPlotDrawList()->AddCircleFilled(cntr,20,IM_COL32(255,255,0,255),20); + ImPlot::GetPlotDrawList()->AddRect(rmin, rmax, IM_COL32(128,0,255,255)); ImPlot::PopPlotClipRect(); ImPlot::EndPlot(); } @@ -1124,10 +1106,10 @@ void StyleSeaborn() { ImPlotStyle& style = ImPlot::GetStyle(); ImVec4* colors = style.Colors; - colors[ImPlotCol_Line] = IMPLOT_COL_AUTO; - colors[ImPlotCol_Fill] = IMPLOT_COL_AUTO; - colors[ImPlotCol_MarkerOutline] = IMPLOT_COL_AUTO; - colors[ImPlotCol_MarkerFill] = IMPLOT_COL_AUTO; + 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); @@ -1200,63 +1182,55 @@ int BinarySearch(const double* arr, int l, int r, double x) { } void PlotCandlestick(const char* label_id, const double* xs, const double* opens, const double* closes, const double* lows, const double* highs, int count, bool tooltip, float width_percent, ImVec4 bullCol, ImVec4 bearCol) { - // get current implot context - ImPlotContext* implot = ImPlot::GetCurrentContext(); - // register item - ImPlotItem* item = ImPlot::RegisterOrGetItem(label_id); - // override legend icon color - item->Color = ImVec4(1,1,1,1); - // return if item not shown (i.e. hidden by legend button) - if (!item->Show) - return; - // fit data if requested - if (implot->FitThisFrame) { - for (int i = 0; i < count; ++i) { - ImPlot::FitPoint(ImPlotPoint(xs[i], lows[i])); - ImPlot::FitPoint(ImPlotPoint(xs[i], highs[i])); + // begin plot item + if (ImPlot::BeginItem(label_id)) { + // override legend icon color + ImPlot::GetCurrentItem()->Color = ImVec4(1,1,1,1); + // fit data if requested + if (ImPlot::FitThisFrame()) { + for (int i = 0; i < count; ++i) { + ImPlot::FitPoint(ImPlotPoint(xs[i], lows[i])); + ImPlot::FitPoint(ImPlotPoint(xs[i], highs[i])); + } } - } - // get ImGui window DrawList - ImDrawList* draw_list = ImGui::GetWindowDrawList(); - // push clip rect for the current plot - ImPlot::PushPlotClipRect(); - // calc real value width - double half_width = count > 1 ? (xs[1] - xs[0]) * width_percent : width_percent; - // render data - for (int i = 0; i < count; ++i) { - ImVec2 open_pos = ImPlot::PlotToPixels(xs[i] - half_width, opens[i]); - ImVec2 close_pos = ImPlot::PlotToPixels(xs[i] + half_width, closes[i]); - ImVec2 low_pos = ImPlot::PlotToPixels(xs[i], lows[i]); - ImVec2 high_pos = ImPlot::PlotToPixels(xs[i], highs[i]); - ImU32 color = ImGui::GetColorU32(opens[i] > closes[i] ? bearCol : bullCol); - draw_list->AddLine(low_pos, high_pos, color); - draw_list->AddRectFilled(open_pos, close_pos, color); - } - // pop clip rect for the current plot - ImPlot::PopPlotClipRect(); - // custom tool - if (!ImPlot::IsPlotHovered() || !tooltip) - return; - ImPlotPoint mouse = ImPlot::GetPlotMousePos(); - mouse.x = round(mouse.x); - float tool_l = ImPlot::PlotToPixels(mouse.x - half_width * 1.5, mouse.y).x; - float tool_r = ImPlot::PlotToPixels(mouse.x + half_width * 1.5, mouse.y).x; - float tool_t = ImPlot::GetPlotPos().y; - float tool_b = tool_t + ImPlot::GetPlotSize().y; - ImPlot::PushPlotClipRect(); - draw_list->AddRectFilled(ImVec2(tool_l, tool_t), ImVec2(tool_r, tool_b), IM_COL32(0,255,255,64)); - ImPlot::PopPlotClipRect(); - // find mouse location index - int idx = BinarySearch(xs, 0, count - 1, mouse.x); - // render tool tip - if (idx != -1) { - ImGui::BeginTooltip(); - ImGui::Text("Day: %.0f", xs[idx]); - ImGui::Text("Open: $%.2f", opens[idx]); - ImGui::Text("Close: $%.2f", closes[idx]); - ImGui::Text("Low: $%.2f", lows[idx]); - ImGui::Text("High: $%.2f", highs[idx]); - ImGui::EndTooltip(); + // get ImGui window DrawList + ImDrawList* draw_list = ImPlot::GetPlotDrawList(); + // calc real value width + double half_width = count > 1 ? (xs[1] - xs[0]) * width_percent : width_percent; + // render data + for (int i = 0; i < count; ++i) { + ImVec2 open_pos = ImPlot::PlotToPixels(xs[i] - half_width, opens[i]); + ImVec2 close_pos = ImPlot::PlotToPixels(xs[i] + half_width, closes[i]); + ImVec2 low_pos = ImPlot::PlotToPixels(xs[i], lows[i]); + ImVec2 high_pos = ImPlot::PlotToPixels(xs[i], highs[i]); + ImU32 color = ImGui::GetColorU32(opens[i] > closes[i] ? bearCol : bullCol); + draw_list->AddLine(low_pos, high_pos, color); + draw_list->AddRectFilled(open_pos, close_pos, color); + } + // custom tool + if (ImPlot::IsPlotHovered() && tooltip) { + ImPlotPoint mouse = ImPlot::GetPlotMousePos(); + mouse.x = round(mouse.x); + float tool_l = ImPlot::PlotToPixels(mouse.x - half_width * 1.5, mouse.y).x; + float tool_r = ImPlot::PlotToPixels(mouse.x + half_width * 1.5, mouse.y).x; + float tool_t = ImPlot::GetPlotPos().y; + float tool_b = tool_t + ImPlot::GetPlotSize().y; + draw_list->AddRectFilled(ImVec2(tool_l, tool_t), ImVec2(tool_r, tool_b), IM_COL32(0,255,255,64)); + // find mouse location index + int idx = BinarySearch(xs, 0, count - 1, mouse.x); + // render tool tip (won't be affected by plot clip rect) + if (idx != -1) { + ImGui::BeginTooltip(); + ImGui::Text("Day: %.0f", xs[idx]); + ImGui::Text("Open: $%.2f", opens[idx]); + ImGui::Text("Close: $%.2f", closes[idx]); + ImGui::Text("Low: $%.2f", lows[idx]); + ImGui::Text("High: $%.2f", highs[idx]); + ImGui::EndTooltip(); + } + } + // end plot item + ImPlot::EndItem(); } } @@ -1300,17 +1274,17 @@ void ShowBenchmarkTool() { t1 = ImGui::GetTime(); } if (L > max_lines) { - running = false; - L = max_lines; - } + running = false; + L = max_lines; + } } ImGui::Text("ImDrawIdx: %d-bit", (int)(sizeof(ImDrawIdx) * 8)); - ImGui::Text("ImGuiBackendFlags_RendererHasVtxOffset: %s", (ImGui::GetIO().BackendFlags & ImGuiBackendFlags_RendererHasVtxOffset) ? "True" : "False"); + ImGui::Text("ImGuiBackendFlags_RendererHasVtxOffset: %s", (ImGui::GetIO().BackendFlags & ImGuiBackendFlags_RendererHasVtxOffset) ? "True" : "False"); ImGui::Text("%.2f FPS", ImGui::GetIO().Framerate); - + ImGui::Separator(); - + bool was_running = running; if (was_running) { ImGui::PushItemFlag(ImGuiItemFlags_Disabled, true); @@ -1324,9 +1298,9 @@ void ShowBenchmarkTool() { t1 = ImGui::GetTime(); } ImGui::SameLine(); - ImGui::Checkbox("Anti-Aliased Lines", &ImPlot::GetStyle().AntiAliasedLines); + ImGui::Checkbox("Anti-Aliased Lines", &ImPlot::GetStyle().AntiAliasedLines); if (was_running) { ImGui::PopItemFlag(); ImGui::PopStyleVar(); } - + ImGui::ProgressBar((float)L / (float)(max_lines - 1)); ImPlot::SetNextPlotLimits(0,1,0,1,ImGuiCond_Always); @@ -1334,9 +1308,8 @@ void ShowBenchmarkTool() { if (running) { for (int i = 0; i < L; ++i) { ImGui::PushID(i); - ImPlot::PushStyleColor(ImPlotCol_Line, items[i].Col); + ImPlot::SetNextLineStyle(items[i].Col); ImPlot::PlotLine("##item", items[i].Data, 1000); - ImPlot::PopStyleColor(); ImGui::PopID(); } } diff --git a/implot_internal.h b/implot_internal.h index 294b454..4475705 100644 --- a/implot_internal.h +++ b/implot_internal.h @@ -143,6 +143,20 @@ struct ImArray { const int Size = N; }; +//----------------------------------------------------------------------------- +// [SECTION] ImPlot Enums +//----------------------------------------------------------------------------- + +typedef int ImPlotScale; // -> enum ImPlotScale_ + +// XY axes scaling combinations +enum ImPlotScale_ { + ImPlotScale_LinLin, // linear x, linear y + ImPlotScale_LogLin, // log x, linear y + ImPlotScale_LinLog, // linear x, log y + ImPlotScale_LogLog // log x, log y +}; + //----------------------------------------------------------------------------- // [SECTION] ImPlot Structs //----------------------------------------------------------------------------- @@ -205,7 +219,7 @@ struct ImPlotTickCollection { Ticks.push_back(tick); Size++; } - + void AddTick(double value, bool major, bool show_label, void (*labeler)(ImPlotTick& tick, ImGuiTextBuffer& buf)) { ImPlotTick tick(value, major, show_label); if (labeler) @@ -217,9 +231,9 @@ struct ImPlotTickCollection { return Labels.Buf.Data + Ticks[idx].BufferOffset; } - void Reset() { - Ticks.shrink(0); - Labels.Buf.shrink(0); + void Reset() { + Ticks.shrink(0); + Labels.Buf.shrink(0); TotalWidth = TotalHeight = MaxWidth = MaxHeight = 0; Size = 0; } @@ -285,7 +299,6 @@ struct ImPlotItem { ImGuiID ID; ImVec4 Color; - ImPlotMarker Marker; int NameOffset; bool Show; bool Highlight; @@ -294,7 +307,6 @@ struct ImPlotItem ImPlotItem() { ID = 0; Color = ImPlot::NextColormapColor(); - Marker = ImPlotMarker_None; NameOffset = -1; Show = true; SeenThisFrame = false; @@ -321,7 +333,6 @@ struct ImPlotState bool Queried; bool DraggingQuery; int ColormapIdx; - int MarkerIdx; int CurrentYAxis; ImPlotState() { @@ -358,11 +369,37 @@ struct ImPlotNextPlotData } }; +// Temporary data storage for upcoming item +struct ImPlotItemStyle { + 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; + bool RenderLine; + bool RenderFill; + bool RenderMarkerLine; + bool RenderMarkerFill; + ImPlotItemStyle() { + for (int i = 0; i < 5; ++i) + Colors[i] = IMPLOT_AUTO_COL; + LineWeight = MarkerWeight = FillAlpha = ErrorBarSize = + ErrorBarSize = ErrorBarWeight = DigitalBitHeight = DigitalBitGap = IMPLOT_AUTO; + Marker = IMPLOT_AUTO; + } +}; + // Holds state information that must persist between calls to BeginPlot()/EndPlot() struct ImPlotContext { // Plot States ImPool Plots; ImPlotState* CurrentPlot; + ImPlotItem* CurrentItem; // Legend ImVector LegendIndices; @@ -385,6 +422,7 @@ struct ImPlotContext { float YAxisReference[IMPLOT_Y_AXES]; // Transformations and Data Extents + ImPlotScale Scales[IMPLOT_Y_AXES]; ImRect PixelRange[IMPLOT_Y_AXES]; double Mx; double My[IMPLOT_Y_AXES]; @@ -423,6 +461,7 @@ struct ImPlotContext { int DigitalPlotItemCnt; int DigitalPlotOffset; ImPlotNextPlotData NextPlotData; + ImPlotItemStyle NextItemStyle; ImPlotInputMap InputMap; ImPlotPoint MousePos[IMPLOT_Y_AXES]; }; @@ -461,6 +500,17 @@ void BustPlotCache(); void UpdateTransformCache(); // Extends the current plots axes so that it encompasses point p void FitPoint(const ImPlotPoint& p); +// Returns true if the user has requested data to be fit. +inline bool FitThisFrame() { return GImPlot->FitThisFrame; } +// Gets the current y-axis for the current plot +inline int GetCurrentYAxis() { return GImPlot->CurrentPlot->CurrentYAxis; } +// Gets the XY scale for the current plot and y-axis +inline ImPlotScale GetCurrentScale() { return GImPlot->Scales[GetCurrentYAxis()]; } + +// Begins a new item. Returns false if the item should not be plotted. Pushes PlotClipRect. +bool BeginItem(const char* label_id, ImPlotCol recolor_from = -1); +// Ends an item (call only if BeginItem returns true). Pops PlotClipRect. +void EndItem(); // Register or get an existing item from the current plot ImPlotItem* RegisterOrGetItem(const char* label_id); @@ -470,9 +520,20 @@ ImPlotItem* GetItem(int i); ImPlotItem* GetItem(const char* label_id); // Gets a plot item from a specific plot ImPlotItem* GetItem(const char* plot_title, const char* item_label_id); +// Gets the current item +ImPlotItem* GetCurrentItem(); // Busts the cache for every item for every plot in the current context. void BustItemCache(); +// Get styling data for next item (call between Begin/EndItem) +inline const ImPlotItemStyle& GetItemStyle() { return GImPlot->NextItemStyle; } + +// Recolors an item legend icon from an the current ImPlotCol if it is not automatic (i.e. alpha != -1) +inline void TryRecolorItem(ImPlotItem* item, ImPlotCol idx) { + if (GImPlot->Style.Colors[idx].w != -1) + item->Color = GImPlot->Style.Colors[idx]; +} + // Returns the number of entries in the current legend int GetLegendCount(); // Gets the ith entry string for the current legend @@ -500,8 +561,6 @@ double NiceNum(double x, bool round); void AddTextVertical(ImDrawList *DrawList, ImVec2 pos, ImU32 col, const char* text_begin, const char* text_end = NULL); // Calculates the size of vertical text ImVec2 CalcTextSizeVertical(const char *text); -// Returns white or black text given background color -inline ImU32 CalcTextColor(const ImVec4& bg) { return (bg.x * 0.299 + bg.y * 0.587 + bg.z * 0.114) > 0.729 ? IM_COL32_BLACK : IM_COL32_WHITE; } // Returns true if val is NAN or INFINITY inline bool NanOrInf(double val) { return val == HUGE_VAL || val == -HUGE_VAL || isnan(val); } @@ -551,68 +610,17 @@ ImVec4 LerpColormap(const ImVec4* colormap, int size, float t); // Resamples a colormap. #size_out must be greater than 1. void ResampleColormap(const ImVec4* colormap_in, int size_in, ImVec4* colormap_out, int size_out); +// Returns true if a color is set to be automatically determined +inline bool IsColorAuto(const ImVec4& col) { return col.w == -1; } // Returns true if a style color is set to be automaticaly determined -inline bool IsColorAuto(ImPlotCol idx) { return GImPlot->Style.Colors[idx].w == -1; } +inline bool IsColorAuto(ImPlotCol idx) { return IsColorAuto(GImPlot->Style.Colors[idx]); } // Returns the automatically deduced style color ImVec4 GetAutoColor(ImPlotCol idx); // Returns the style color whether it is automatic or custom set inline ImVec4 GetStyleColorVec4(ImPlotCol idx) {return IsColorAuto(idx) ? GetAutoColor(idx) : GImPlot->Style.Colors[idx]; } inline ImU32 GetStyleColorU32(ImPlotCol idx) { return ImGui::ColorConvertFloat4ToU32(GetStyleColorVec4(idx)); } - -// Recolors an item legend icon from an the current ImPlotCol if it is not automatic (i.e. alpha != -1) -inline void TryRecolorItem(ImPlotItem* item, ImPlotCol idx) { - if (GImPlot->Style.Colors[idx].w != -1) - item->Color = GImPlot->Style.Colors[idx]; -} - -// Returns true if lines will render (e.g. basic lines, bar outlines) -inline bool WillLineRender() { - return GImPlot->Style.Colors[ImPlotCol_Line].w != 0 && GImPlot->Style.LineWeight > 0; -} - -// Returns true if fills will render (e.g. shaded plots, bar fills) -inline bool WillFillRender() { - return GImPlot->Style.Colors[ImPlotCol_Fill].w != 0 && GImPlot->Style.FillAlpha > 0; -} - -// Returns true if marker outlines will render -inline bool WillMarkerOutlineRender() { - return GImPlot->Style.Colors[ImPlotCol_MarkerOutline].w != 0 && GImPlot->Style.MarkerWeight > 0; -} - -// Returns true if mark fill will render -inline bool WillMarkerFillRender() { - return GImPlot->Style.Colors[ImPlotCol_MarkerFill].w != 0 && GImPlot->Style.FillAlpha > 0; -} - -// Gets the line color for an item -inline ImVec4 GetLineColor(ImPlotItem* item) { - return IsColorAuto(ImPlotCol_Line) ? item->Color : GImPlot->Style.Colors[ImPlotCol_Line]; -} - -// Gets the fill color for an item -inline ImVec4 GetItemFillColor(ImPlotItem* item) { - ImVec4 col = IsColorAuto(ImPlotCol_Fill) ? item->Color : GImPlot->Style.Colors[ImPlotCol_Fill]; - col.w *= GImPlot->Style.FillAlpha; - return col; -} - -// Gets the marker outline color for an item -inline ImVec4 GetMarkerOutlineColor(ImPlotItem* item) { - return IsColorAuto(ImPlotCol_MarkerOutline) ? GetLineColor(item) : GImPlot->Style.Colors[ImPlotCol_MarkerOutline]; -} - -// Gets the marker fill color for an item -inline ImVec4 GetMarkerFillColor(ImPlotItem* item) { - ImVec4 col = IsColorAuto(ImPlotCol_MarkerFill) ? GetLineColor(item) :GImPlot->Style.Colors[ImPlotCol_MarkerFill]; - col.w *= GImPlot->Style.FillAlpha; - return col; -} - -// Gets the error bar color -inline ImVec4 GetErrorBarColor() { - return GetStyleColorVec4(ImPlotCol_ErrorBar); -} +// Returns white or black text given background color +inline ImU32 CalcTextColor(const ImVec4& bg) { return (bg.x * 0.299 + bg.y * 0.587 + bg.z * 0.114) > 0.729 ? IM_COL32_BLACK : IM_COL32_WHITE; } //----------------------------------------------------------------------------- // [SECTION] Internal / Experimental Plotters diff --git a/implot_items.cpp b/implot_items.cpp index 6aa4dfa..ed15992 100644 --- a/implot_items.cpp +++ b/implot_items.cpp @@ -44,6 +44,163 @@ namespace ImPlot { +//----------------------------------------------------------------------------- +// Item Utils +//----------------------------------------------------------------------------- + +ImPlotItem* RegisterOrGetItem(const char* label_id) { + ImPlotContext& gp = *GImPlot; + ImGuiID id = ImGui::GetID(label_id); + ImPlotItem* item = gp.CurrentPlot->Items.GetOrAddByKey(id); + if (item->SeenThisFrame) + return item; + item->SeenThisFrame = true; + int idx = gp.CurrentPlot->Items.GetIndex(item); + item->ID = id; + if (ImGui::FindRenderedTextEnd(label_id, NULL) != label_id) { + gp.LegendIndices.push_back(idx); + item->NameOffset = gp.LegendLabels.size(); + gp.LegendLabels.append(label_id, label_id + strlen(label_id) + 1); + } + else { + item->Show = true; + } + if (item->Show) + gp.VisibleItemCount++; + return item; +} + +ImPlotItem* GetItem(int i) { + ImPlotContext& gp = *GImPlot; + return gp.CurrentPlot->Items.GetByIndex(gp.LegendIndices[i]); +} + +ImPlotItem* GetItem(const char* label_id) { + ImPlotContext& gp = *GImPlot; + ImGuiID id = ImGui::GetID(label_id); + return gp.CurrentPlot->Items.GetByKey(id); +} + +ImPlotItem* GetItem(const char* plot_title, const char* item_label_id) { + ImPlotState* plot = GetPlot(plot_title); + if (plot) { + ImGuiID id = ImGui::GetID(item_label_id); + return plot->Items.GetByKey(id); + } + return NULL; +} + +ImPlotItem* GetCurrentItem() { + ImPlotContext& gp = *GImPlot; + return gp.CurrentItem; +} + +void BustItemCache() { + ImPlotContext& gp = *GImPlot; + for (int p = 0; p < gp.Plots.GetSize(); ++p) { + ImPlotState& plot = *gp.Plots.GetByIndex(p); + plot.ColormapIdx = 0; + plot.Items.Clear(); + } +} + +// Begins a new item. Returns false if the item should not be plotted. +bool BeginItem(const char* label_id, ImPlotCol recolor_from) { + ImPlotContext& gp = *GImPlot; + IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "PlotX() needs to be called between BeginPlot() and EndPlot()!"); + ImPlotItem* item = RegisterOrGetItem(label_id); + if (!item->Show) { + // reset next item data + gp.NextItemStyle = ImPlotItemStyle(); + return false; + } + else { + // set current item + gp.CurrentItem = item; + ImPlotItemStyle& s = gp.NextItemStyle; + // override item color + if (recolor_from != -1) { + if (!IsColorAuto(s.Colors[recolor_from])) + item->Color = s.Colors[recolor_from]; + else if (!IsColorAuto(gp.Style.Colors[recolor_from])) + item->Color = gp.Style.Colors[recolor_from]; + } + // 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 + // apply highlight mods + if (item->Highlight) { + s.LineWeight *= 2; + s.MarkerWeight *= 2; + // TODO: highlight fills? + } + // set render flags + s.RenderLine = s.Colors[ImPlotCol_Line].w > 0 && s.LineWeight > 0; + s.RenderFill = s.Colors[ImPlotCol_Fill].w > 0; + s.RenderMarkerLine = s.Colors[ImPlotCol_MarkerOutline].w > 0 && s.MarkerWeight > 0; + s.RenderMarkerFill = s.Colors[ImPlotCol_MarkerFill].w > 0; + // push rendering clip rect + PushPlotClipRect(); + return true; + } +} + +// Ends an item (call only if BeginItem returns true) +void EndItem() { + ImPlotContext& gp = *GImPlot; + // pop rendering clip rect + PopPlotClipRect(); + // reset next item data + gp.NextItemStyle = ImPlotItemStyle(); + // set current item + gp.CurrentItem = NULL; +} + +void SetNextLineStyle(const ImVec4& col, float weight) { + ImPlotContext& gp = *GImPlot; + gp.NextItemStyle.Colors[ImPlotCol_Line] = col; + gp.NextItemStyle.LineWeight = weight; +} + +void SetNextFillStyle(const ImVec4& col, float alpha) { + ImPlotContext& gp = *GImPlot; + gp.NextItemStyle.Colors[ImPlotCol_Fill] = col; + gp.NextItemStyle.FillAlpha = alpha; +} + +void SetNextMarkerStyle(ImPlotMarker marker, float size, const ImVec4& fill, float weight, const ImVec4& outline) { + ImPlotContext& gp = *GImPlot; + gp.NextItemStyle.Marker = marker; + gp.NextItemStyle.Colors[ImPlotCol_MarkerFill] = fill; + gp.NextItemStyle.MarkerSize = size; + gp.NextItemStyle.Colors[ImPlotCol_MarkerOutline] = outline; + gp.NextItemStyle.MarkerWeight = weight; +} + +void SetNextErrorBarStyle(const ImVec4& col, float size, float weight) { + ImPlotContext& gp = *GImPlot; + gp.NextItemStyle.Colors[ImPlotCol_ErrorBar] = col; + gp.NextItemStyle.ErrorBarSize = size; + gp.NextItemStyle.ErrorBarWeight = weight; +} + + //----------------------------------------------------------------------------- // GETTERS //----------------------------------------------------------------------------- @@ -202,10 +359,11 @@ struct GetterError { //----------------------------------------------------------------------------- // Transforms convert points in plot space (i.e. ImPlotPoint) to pixel space (i.e. ImVec2) +// TODO: Cache transformation variables // Transforms points for linear x and linear y space struct TransformerLinLin { - TransformerLinLin(int y_axis) : YAxis(y_axis) {} + TransformerLinLin() : YAxis(GetCurrentYAxis()) {} inline ImVec2 operator()(const ImPlotPoint& plt) { return (*this)(plt.x, plt.y); } inline ImVec2 operator()(double x, double y) { @@ -219,7 +377,7 @@ struct TransformerLinLin { // Transforms points for log x and linear y space struct TransformerLogLin { - TransformerLogLin(int y_axis) : YAxis(y_axis) {} + TransformerLogLin() : YAxis(GetCurrentYAxis()) {} inline ImVec2 operator()(const ImPlotPoint& plt) { return (*this)(plt.x, plt.y); } inline ImVec2 operator()(double x, double y) { @@ -235,7 +393,7 @@ struct TransformerLogLin { // Transforms points for linear x and log y space struct TransformerLinLog { - TransformerLinLog(int y_axis) : YAxis(y_axis) {} + TransformerLinLog() : YAxis(GetCurrentYAxis()) {} inline ImVec2 operator()(const ImPlotPoint& plt) { return (*this)(plt.x, plt.y); } inline ImVec2 operator()(double x, double y) { @@ -250,7 +408,7 @@ struct TransformerLinLog { // Transforms points for log x and log y space struct TransformerLogLog { - TransformerLogLog(int y_axis) : YAxis(y_axis) {} + TransformerLogLog() : YAxis(GetCurrentYAxis()) {} inline ImVec2 operator()(const ImPlotPoint& plt) { return (*this)(plt.x, plt.y); } inline ImVec2 operator()(double x, double y) { @@ -583,25 +741,24 @@ inline void RenderMarkerCross(ImDrawList& DrawList, const ImVec2& c, float s, bo } template -inline void RenderMarkers(Getter getter, Transformer transformer, ImDrawList& DrawList, bool rend_mk_line, ImU32 col_mk_line, bool rend_mk_fill, ImU32 col_mk_fill) { - static void (*marker_table[])(ImDrawList&, const ImVec2&, float s, bool, ImU32, bool, ImU32, float) = { - NULL, - RenderMarkerCircle, - RenderMarkerSquare, - RenderMarkerDiamond , - RenderMarkerUp , - RenderMarkerDown , - RenderMarkerLeft, - RenderMarkerRight, - RenderMarkerCross, - RenderMarkerPlus, +inline void RenderMarkers(Getter getter, Transformer transformer, ImDrawList& DrawList, ImPlotMarker marker, float size, bool rend_mk_line, ImU32 col_mk_line, float weight, bool rend_mk_fill, ImU32 col_mk_fill) { + static void (*marker_table[])(ImDrawList&, const ImVec2&, float s, bool, ImU32, bool, ImU32, float) = { + RenderMarkerCircle, + RenderMarkerSquare, + RenderMarkerDiamond , + RenderMarkerUp , + RenderMarkerDown , + RenderMarkerLeft, + RenderMarkerRight, + RenderMarkerCross, + RenderMarkerPlus, RenderMarkerAsterisk }; ImPlotContext& gp = *GImPlot; for (int i = 0; i < getter.Count; ++i) { ImVec2 c = transformer(getter(i)); - if (gp.BB_Plot.Contains(c)) - marker_table[gp.Style.Marker](DrawList, c, gp.Style.MarkerSize, rend_mk_line, col_mk_line, rend_mk_fill, col_mk_fill, gp.Style.MarkerWeight); + if (gp.BB_Plot.Contains(c)) + marker_table[marker](DrawList, c, size, rend_mk_line, col_mk_line, rend_mk_fill, col_mk_fill, weight); } } @@ -610,159 +767,145 @@ inline void RenderMarkers(Getter getter, Transformer transformer, ImDrawList& Dr //----------------------------------------------------------------------------- template -inline void PlotEx(const char* label_id, Getter getter) -{ - ImPlotContext& gp = *GImPlot; - IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "PlotEx() needs to be called between BeginPlot() and EndPlot()!"); - - ImPlotItem* item = RegisterOrGetItem(label_id); - if (!item->Show) - return; - TryRecolorItem(item, ImPlotCol_Line); - - // find data extents - if (gp.FitThisFrame) { - for (int i = 0; i < getter.Count; ++i) { - ImPlotPoint p = getter(i); - FitPoint(p); +inline void PlotLineEx(const char* label_id, Getter getter) { + if (BeginItem(label_id, ImPlotCol_Line)) { + if (FitThisFrame()) { + for (int i = 0; i < getter.Count; ++i) { + ImPlotPoint p = getter(i); + FitPoint(p); + } } + const ImPlotItemStyle& s = GetItemStyle(); + ImDrawList& DrawList = *GetPlotDrawList(); + if (getter.Count > 1 && s.RenderLine) { + const ImU32 col_line = ImGui::GetColorU32(s.Colors[ImPlotCol_Line]); + switch (GetCurrentScale()) { + case ImPlotScale_LinLin: RenderLineStrip(getter, TransformerLinLin(), DrawList, s.LineWeight, col_line); break; + case ImPlotScale_LogLin: RenderLineStrip(getter, TransformerLogLin(), DrawList, s.LineWeight, col_line); break; + case ImPlotScale_LinLog: RenderLineStrip(getter, TransformerLinLog(), DrawList, s.LineWeight, col_line); break; + case ImPlotScale_LogLog: RenderLineStrip(getter, TransformerLogLog(), DrawList, s.LineWeight, col_line); break; + } + } + // render markers + if (s.Marker != ImPlotMarker_None) { + const ImU32 col_line = ImGui::GetColorU32(s.Colors[ImPlotCol_MarkerOutline]); + const ImU32 col_fill = ImGui::GetColorU32(s.Colors[ImPlotCol_MarkerFill]); + switch (GetCurrentScale()) { + case ImPlotScale_LinLin: RenderMarkers(getter, TransformerLinLin(), DrawList, s.Marker, s.MarkerSize, s.RenderMarkerLine, col_line, s.MarkerWeight, s.RenderMarkerFill, col_fill); break; + case ImPlotScale_LogLin: RenderMarkers(getter, TransformerLogLin(), DrawList, s.Marker, s.MarkerSize, s.RenderMarkerLine, col_line, s.MarkerWeight, s.RenderMarkerFill, col_fill); break; + case ImPlotScale_LinLog: RenderMarkers(getter, TransformerLinLog(), DrawList, s.Marker, s.MarkerSize, s.RenderMarkerLine, col_line, s.MarkerWeight, s.RenderMarkerFill, col_fill); break; + case ImPlotScale_LogLog: RenderMarkers(getter, TransformerLogLog(), DrawList, s.Marker, s.MarkerSize, s.RenderMarkerLine, col_line, s.MarkerWeight, s.RenderMarkerFill, col_fill); break; + } + } + EndItem(); } - - ImDrawList& DrawList = *ImGui::GetWindowDrawList(); - ImPlotState* plot = gp.CurrentPlot; - const int y_axis = plot->CurrentYAxis; - - PushPlotClipRect(); - // render line - if (getter.Count > 1 && WillLineRender()) { - ImU32 col_line = ImGui::GetColorU32(GetLineColor(item)); - const float line_weight = item->Highlight ? gp.Style.LineWeight * 2 : gp.Style.LineWeight; - if (ImHasFlag(plot->XAxis.Flags, ImPlotAxisFlags_LogScale) && ImHasFlag(plot->YAxis[y_axis].Flags, ImPlotAxisFlags_LogScale)) - RenderLineStrip(getter, TransformerLogLog(y_axis), DrawList, line_weight, col_line); - else if (ImHasFlag(plot->XAxis.Flags, ImPlotAxisFlags_LogScale)) - RenderLineStrip(getter, TransformerLogLin(y_axis), DrawList, line_weight, col_line); - else if (ImHasFlag(plot->YAxis[y_axis].Flags, ImPlotAxisFlags_LogScale)) - RenderLineStrip(getter, TransformerLinLog(y_axis), DrawList, line_weight, col_line); - else - RenderLineStrip(getter, TransformerLinLin(y_axis), DrawList, line_weight, col_line); - } - // render markers - if (gp.Style.Marker != ImPlotMarker_None) { - const bool rend_mk_line = WillMarkerOutlineRender(); - const bool rend_mk_fill = WillMarkerFillRender(); - const ImU32 col_mk_line = ImGui::GetColorU32(GetMarkerOutlineColor(item)); - const ImU32 col_mk_fill = ImGui::GetColorU32(GetMarkerFillColor(item)); - if (ImHasFlag(plot->XAxis.Flags, ImPlotAxisFlags_LogScale) && ImHasFlag(plot->YAxis[y_axis].Flags, ImPlotAxisFlags_LogScale)) - RenderMarkers(getter, TransformerLogLog(y_axis), DrawList, rend_mk_line, col_mk_line, rend_mk_fill, col_mk_fill); - else if (ImHasFlag(plot->XAxis.Flags, ImPlotAxisFlags_LogScale)) - RenderMarkers(getter, TransformerLogLin(y_axis), DrawList, rend_mk_line, col_mk_line, rend_mk_fill, col_mk_fill); - else if (ImHasFlag(plot->YAxis[y_axis].Flags, ImPlotAxisFlags_LogScale)) - RenderMarkers(getter, TransformerLinLog(y_axis), DrawList, rend_mk_line, col_mk_line, rend_mk_fill, col_mk_fill); - else - RenderMarkers(getter, TransformerLinLin(y_axis), DrawList, rend_mk_line, col_mk_line, rend_mk_fill, col_mk_fill); - } - PopPlotClipRect(); } - // float void PlotLine(const char* label_id, const float* values, int count, int offset, int stride) { GetterYs getter(values,count,offset,stride); - PlotEx(label_id, getter); + PlotLineEx(label_id, getter); } void PlotLine(const char* label_id, const float* xs, const float* ys, int count, int offset, int stride) { GetterXsYs getter(xs,ys,count,offset,stride); - return PlotEx(label_id, getter); + return PlotLineEx(label_id, getter); } void PlotLine(const char* label_id, const ImVec2* data, int count, int offset) { GetterImVec2 getter(data, count, offset); - return PlotEx(label_id, getter); + return PlotLineEx(label_id, getter); } - // double void PlotLine(const char* label_id, const double* values, int count, int offset, int stride) { GetterYs getter(values,count,offset,stride); - PlotEx(label_id, getter); + PlotLineEx(label_id, getter); } void PlotLine(const char* label_id, const double* xs, const double* ys, int count, int offset, int stride) { GetterXsYs getter(xs,ys,count,offset,stride); - return PlotEx(label_id, getter); + return PlotLineEx(label_id, getter); } void PlotLine(const char* label_id, const ImPlotPoint* data, int count, int offset) { GetterImPlotPoint getter(data, count, offset); - return PlotEx(label_id, getter); + return PlotLineEx(label_id, getter); } - // custom void PlotLine(const char* label_id, ImPlotPoint (*getter_func)(void* data, int idx), void* data, int count, int offset) { GetterFuncPtrImPlotPoint getter(getter_func,data, count, offset); - return PlotEx(label_id, getter); + return PlotLineEx(label_id, getter); } //----------------------------------------------------------------------------- // PLOT SCATTER //----------------------------------------------------------------------------- -inline int PushScatterStyle() { - int vars = 1; - PushStyleVar(ImPlotStyleVar_LineWeight, 0); - if (GetStyle().Marker == ImPlotMarker_None) { - PushStyleVar(ImPlotStyleVar_Marker, ImPlotMarker_Circle); - vars++; +template +inline void PlotScatterEx(const char* label_id, Getter getter) { + if (BeginItem(label_id, ImPlotCol_MarkerOutline)) { + if (FitThisFrame()) { + for (int i = 0; i < getter.Count; ++i) { + ImPlotPoint p = getter(i); + FitPoint(p); + } + } + const ImPlotItemStyle& s = GetItemStyle(); + ImDrawList& DrawList = *GetPlotDrawList(); + // render markers + ImPlotMarker marker = s.Marker == ImPlotMarker_None ? ImPlotMarker_Circle : s.Marker; + if (marker != ImPlotMarker_None) { + const ImU32 col_line = ImGui::GetColorU32(s.Colors[ImPlotCol_MarkerOutline]); + const ImU32 col_fill = ImGui::GetColorU32(s.Colors[ImPlotCol_MarkerFill]); + switch (GetCurrentScale()) { + case ImPlotScale_LinLin: RenderMarkers(getter, TransformerLinLin(), DrawList, marker, s.MarkerSize, s.RenderMarkerLine, col_line, s.MarkerWeight, s.RenderMarkerFill, col_fill); break; + case ImPlotScale_LogLin: RenderMarkers(getter, TransformerLogLin(), DrawList, marker, s.MarkerSize, s.RenderMarkerLine, col_line, s.MarkerWeight, s.RenderMarkerFill, col_fill); break; + case ImPlotScale_LinLog: RenderMarkers(getter, TransformerLinLog(), DrawList, marker, s.MarkerSize, s.RenderMarkerLine, col_line, s.MarkerWeight, s.RenderMarkerFill, col_fill); break; + case ImPlotScale_LogLog: RenderMarkers(getter, TransformerLogLog(), DrawList, marker, s.MarkerSize, s.RenderMarkerLine, col_line, s.MarkerWeight, s.RenderMarkerFill, col_fill); break; + } + } + EndItem(); } - return vars; } // float void PlotScatter(const char* label_id, const float* values, int count, int offset, int stride) { - int vars = PushScatterStyle(); - PlotLine(label_id, values, count, offset, stride); - PopStyleVar(vars); + GetterYs getter(values,count,offset,stride); + PlotScatterEx(label_id, getter); } void PlotScatter(const char* label_id, const float* xs, const float* ys, int count, int offset, int stride) { - int vars = PushScatterStyle(); - PlotLine(label_id, xs, ys, count, offset, stride); - PopStyleVar(vars); + GetterXsYs getter(xs,ys,count,offset,stride); + return PlotScatterEx(label_id, getter); } void PlotScatter(const char* label_id, const ImVec2* data, int count, int offset) { - int vars = PushScatterStyle(); - PlotLine(label_id, data, count, offset); - PopStyleVar(vars); + GetterImVec2 getter(data, count, offset); + return PlotScatterEx(label_id, getter); } // double void PlotScatter(const char* label_id, const double* values, int count, int offset, int stride) { - int vars = PushScatterStyle(); - PlotLine(label_id, values, count, offset, stride); - PopStyleVar(vars); + GetterYs getter(values,count,offset,stride); + PlotScatterEx(label_id, getter); } void PlotScatter(const char* label_id, const double* xs, const double* ys, int count, int offset, int stride) { - int vars = PushScatterStyle(); - PlotLine(label_id, xs, ys, count, offset, stride); - PopStyleVar(vars); + GetterXsYs getter(xs,ys,count,offset,stride); + return PlotScatterEx(label_id, getter); } void PlotScatter(const char* label_id, const ImPlotPoint* data, int count, int offset) { - int vars = PushScatterStyle(); - PlotLine(label_id, data, count, offset); - PopStyleVar(vars); + GetterImPlotPoint getter(data, count, offset); + return PlotScatterEx(label_id, getter); } - // custom -void PlotScatter(const char* label_id, ImPlotPoint (*getter)(void* data, int idx), void* data, int count, int offset) { - int vars = PushScatterStyle(); - PlotLine(label_id, getter, data, count, offset); - PopStyleVar(vars); +void PlotScatter(const char* label_id, ImPlotPoint (*getter_func)(void* data, int idx), void* data, int count, int offset) { + GetterFuncPtrImPlotPoint getter(getter_func,data, count, offset); + return PlotScatterEx(label_id, getter); } //----------------------------------------------------------------------------- @@ -771,47 +914,31 @@ void PlotScatter(const char* label_id, ImPlotPoint (*getter)(void* data, int idx template inline void PlotShadedEx(const char* label_id, Getter1 getter1, Getter2 getter2) { - ImPlotContext& gp = *GImPlot; - IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "PlotShaded() needs to be called between BeginPlot() and EndPlot()!"); - - ImPlotItem* item = RegisterOrGetItem(label_id); - if (!item->Show) - return; - TryRecolorItem(item, ImPlotCol_Fill); - - if (!WillFillRender()) - return; - - // find data extents - if (gp.FitThisFrame) { - for (int i = 0; i < ImMin(getter1.Count, getter2.Count); ++i) { - ImPlotPoint p1 = getter1(i); - ImPlotPoint p2 = getter2(i); - FitPoint(p1); - FitPoint(p2); + if (BeginItem(label_id, ImPlotCol_Fill)) { + if (FitThisFrame()) { + for (int i = 0; i < ImMin(getter1.Count, getter2.Count); ++i) { + ImPlotPoint p1 = getter1(i); + ImPlotPoint p2 = getter2(i); + FitPoint(p1); + FitPoint(p2); + } } + const ImPlotItemStyle& s = GetItemStyle(); + ImDrawList & DrawList = *GetPlotDrawList(); + if (s.RenderFill) { + ImU32 col = ImGui::GetColorU32(s.Colors[ImPlotCol_Fill]); + switch (GetCurrentScale()) { + case ImPlotScale_LinLin: RenderPrimitives(ShadedRenderer(getter1,getter2,TransformerLinLin(), col), DrawList); break; + case ImPlotScale_LogLin: RenderPrimitives(ShadedRenderer(getter1,getter2,TransformerLogLin(), col), DrawList); break; + case ImPlotScale_LinLog: RenderPrimitives(ShadedRenderer(getter1,getter2,TransformerLinLog(), col), DrawList); break; + case ImPlotScale_LogLog: RenderPrimitives(ShadedRenderer(getter1,getter2,TransformerLogLog(), col), DrawList); break; + } + } + EndItem(); } - - ImDrawList & DrawList = *ImGui::GetWindowDrawList(); - ImPlotState* plot = gp.CurrentPlot; - const int y_axis = plot->CurrentYAxis; - - ImU32 col = ImGui::GetColorU32(GetItemFillColor(item)); - - PushPlotClipRect(); - if (ImHasFlag(plot->XAxis.Flags, ImPlotAxisFlags_LogScale) && ImHasFlag(plot->YAxis[y_axis].Flags, ImPlotAxisFlags_LogScale)) - RenderPrimitives(ShadedRenderer(getter1,getter2,TransformerLogLog(y_axis), col), DrawList); - else if (ImHasFlag(plot->XAxis.Flags, ImPlotAxisFlags_LogScale)) - RenderPrimitives(ShadedRenderer(getter1,getter2,TransformerLogLin(y_axis), col), DrawList); - else if (ImHasFlag(plot->YAxis[y_axis].Flags, ImPlotAxisFlags_LogScale)) - RenderPrimitives(ShadedRenderer(getter1,getter2,TransformerLinLog(y_axis), col), DrawList); - else - RenderPrimitives(ShadedRenderer(getter1,getter2,TransformerLinLin(y_axis), col), DrawList); - PopPlotClipRect(); } // float - void PlotShaded(const char* label_id, const float* values, int count, float y_ref, int offset, int stride) { GetterYs getter1(values,count,offset,stride); GetterYRef getter2(y_ref, count); @@ -859,47 +986,39 @@ void PlotShaded(const char* label_id, ImPlotPoint (*g1)(void* data, int idx), vo // PLOT BAR V //----------------------------------------------------------------------------- +// TODO: Migrate to RenderPrimitives + template void PlotBarsEx(const char* label_id, Getter getter, TWidth width) { - ImPlotContext& gp = *GImPlot; - IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "PlotBars() needs to be called between BeginPlot() and EndPlot()!"); - - ImPlotItem* item = RegisterOrGetItem(label_id); - if (!item->Show) - return; - TryRecolorItem(item, ImPlotCol_Fill); - - const TWidth half_width = width / 2; - // find data extents - if (gp.FitThisFrame) { + if (BeginItem(label_id, ImPlotCol_Fill)) { + const TWidth half_width = width / 2; + if (FitThisFrame()) { + for (int i = 0; i < getter.Count; ++i) { + ImPlotPoint p = getter(i); + FitPoint(ImPlotPoint(p.x - half_width, p.y)); + FitPoint(ImPlotPoint(p.x + half_width, 0)); + } + } + const ImPlotItemStyle& s = GetItemStyle(); + ImDrawList& DrawList = *GetPlotDrawList(); + ImU32 col_line = ImGui::GetColorU32(s.Colors[ImPlotCol_Line]); + ImU32 col_fill = ImGui::GetColorU32(s.Colors[ImPlotCol_Fill]); + bool rend_line = s.RenderLine; + if (s.RenderFill && col_line == col_fill) + rend_line = false; for (int i = 0; i < getter.Count; ++i) { ImPlotPoint p = getter(i); - FitPoint(ImPlotPoint(p.x - half_width, p.y)); - FitPoint(ImPlotPoint(p.x + half_width, 0)); + if (p.y == 0) + continue; + ImVec2 a = PlotToPixels(p.x - half_width, p.y); + ImVec2 b = PlotToPixels(p.x + half_width, 0); + if (s.RenderFill) + DrawList.AddRectFilled(a, b, col_fill); + if (rend_line) + DrawList.AddRect(a, b, col_line, 0, ImDrawCornerFlags_All, s.LineWeight); } + EndItem(); } - - ImU32 col_line = ImGui::GetColorU32(GetLineColor(item)); - ImU32 col_fill = ImGui::GetColorU32(GetItemFillColor(item)); - const bool rend_fill = WillFillRender(); - bool rend_line = WillLineRender(); - if (rend_fill && col_line == col_fill) - rend_line = false; - - ImDrawList & DrawList = *ImGui::GetWindowDrawList(); - PushPlotClipRect(); - for (int i = 0; i < getter.Count; ++i) { - ImPlotPoint p = getter(i); - if (p.y == 0) - continue; - ImVec2 a = PlotToPixels(p.x - half_width, p.y); - ImVec2 b = PlotToPixels(p.x + half_width, 0); - if (rend_fill) - DrawList.AddRectFilled(a, b, col_fill); - if (rend_line) - DrawList.AddRect(a, b, col_line, 0, ImDrawCornerFlags_All, gp.Style.LineWeight); - } - PopPlotClipRect(); } // float @@ -938,45 +1057,35 @@ void PlotBars(const char* label_id, ImPlotPoint (*getter_func)(void* data, int i template void PlotBarsHEx(const char* label_id, Getter getter, THeight height) { - ImPlotContext& gp = *GImPlot; - IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "PlotBarsH() needs to be called between BeginPlot() and EndPlot()!"); - - ImPlotItem* item = RegisterOrGetItem(label_id); - if (!item->Show) - return; - TryRecolorItem(item, ImPlotCol_Fill); - - const THeight half_height = height / 2; - // find data extents - if (gp.FitThisFrame) { + if (BeginItem(label_id, ImPlotCol_Fill)) { + const THeight half_height = height / 2; + if (FitThisFrame()) { + for (int i = 0; i < getter.Count; ++i) { + ImPlotPoint p = getter(i); + FitPoint(ImPlotPoint(0, p.y - half_height)); + FitPoint(ImPlotPoint(p.x, p.y + half_height)); + } + } + const ImPlotItemStyle& s = GetItemStyle(); + ImDrawList& DrawList = *GetPlotDrawList(); + ImU32 col_line = ImGui::GetColorU32(s.Colors[ImPlotCol_Line]); + ImU32 col_fill = ImGui::GetColorU32(s.Colors[ImPlotCol_Fill]); + bool rend_line = s.RenderLine; + if (s.RenderFill && col_line == col_fill) + rend_line = false; for (int i = 0; i < getter.Count; ++i) { ImPlotPoint p = getter(i); - FitPoint(ImPlotPoint(0, p.y - half_height)); - FitPoint(ImPlotPoint(p.x, p.y + half_height)); + if (p.x == 0) + continue; + ImVec2 a = PlotToPixels(0, p.y - half_height); + ImVec2 b = PlotToPixels(p.x, p.y + half_height); + if (s.RenderFill) + DrawList.AddRectFilled(a, b, col_fill); + if (rend_line) + DrawList.AddRect(a, b, col_line, 0, ImDrawCornerFlags_All, s.LineWeight); } + EndItem(); } - - ImU32 col_line = ImGui::GetColorU32(GetLineColor(item)); - ImU32 col_fill = ImGui::GetColorU32(GetItemFillColor(item)); - const bool rend_fill = WillFillRender(); - bool rend_line = WillLineRender(); - if (rend_fill && col_line == col_fill) - rend_line = false; - - PushPlotClipRect(); - ImDrawList & DrawList = *ImGui::GetWindowDrawList(); - for (int i = 0; i < getter.Count; ++i) { - ImPlotPoint p = getter(i); - if (p.x == 0) - continue; - ImVec2 a = PlotToPixels(0, p.y - half_height); - ImVec2 b = PlotToPixels(p.x, p.y + half_height); - if (rend_fill) - DrawList.AddRectFilled(a, b, col_fill); - if (rend_line) - DrawList.AddRect(a, b, col_line, 0, ImDrawCornerFlags_All, gp.Style.LineWeight); - } - PopPlotClipRect(); } // float @@ -1013,40 +1122,31 @@ void PlotBarsH(const char* label_id, ImPlotPoint (*getter_func)(void* data, int template void PlotErrorBarsEx(const char* label_id, Getter getter) { - ImPlotContext& gp = *GImPlot; - IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "PlotErrorBars() needs to be called between BeginPlot() and EndPlot()!"); - - ImPlotItem* item = RegisterOrGetItem(label_id); - if (!item->Show) - return; - - // find data extents - if (gp.FitThisFrame) { + if (BeginItem(label_id)) { + if (FitThisFrame()) { + for (int i = 0; i < getter.Count; ++i) { + ImPlotPointError e = getter(i); + FitPoint(ImPlotPoint(e.X , e.Y - e.Neg)); + FitPoint(ImPlotPoint(e.X , e.Y + e.Pos )); + } + } + const ImPlotItemStyle& s = GetItemStyle(); + ImDrawList& DrawList = *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; for (int i = 0; i < getter.Count; ++i) { ImPlotPointError e = getter(i); - FitPoint(ImPlotPoint(e.X , e.Y - e.Neg)); - FitPoint(ImPlotPoint(e.X , e.Y + e.Pos )); + ImVec2 p1 = PlotToPixels(e.X, e.Y - e.Neg); + ImVec2 p2 = PlotToPixels(e.X, e.Y + e.Pos); + DrawList.AddLine(p1,p2,col, s.ErrorBarWeight); + if (rend_whisker) { + DrawList.AddLine(p1 - ImVec2(half_whisker, 0), p1 + ImVec2(half_whisker, 0), col, s.ErrorBarWeight); + DrawList.AddLine(p2 - ImVec2(half_whisker, 0), p2 + ImVec2(half_whisker, 0), col, s.ErrorBarWeight); + } } + EndItem(); } - - const ImU32 col = ImGui::GetColorU32(GetErrorBarColor()); - const bool rend_whisker = gp.Style.ErrorBarSize > 0; - const float half_whisker = gp.Style.ErrorBarSize * 0.5f; - - ImDrawList & DrawList = *ImGui::GetWindowDrawList(); - - PushPlotClipRect(); - for (int i = 0; i < getter.Count; ++i) { - ImPlotPointError e = getter(i); - ImVec2 p1 = PlotToPixels(e.X, e.Y - e.Neg); - ImVec2 p2 = PlotToPixels(e.X, e.Y + e.Pos); - DrawList.AddLine(p1,p2,col, gp.Style.ErrorBarWeight); - if (rend_whisker) { - DrawList.AddLine(p1 - ImVec2(half_whisker, 0), p1 + ImVec2(half_whisker, 0), col, gp.Style.ErrorBarWeight); - DrawList.AddLine(p2 - ImVec2(half_whisker, 0), p2 + ImVec2(half_whisker, 0), col, gp.Style.ErrorBarWeight); - } - } - PopPlotClipRect(); } // float @@ -1077,40 +1177,31 @@ void PlotErrorBars(const char* label_id, const double* xs, const double* ys, con template void PlotErrorBarsHEx(const char* label_id, Getter getter) { - ImPlotContext& gp = *GImPlot; - IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "PlotErrorBarsH() needs to be called between BeginPlot() and EndPlot()!"); - - ImPlotItem* item = RegisterOrGetItem(label_id); - if (!item->Show) - return; - - // find data extents - if (gp.FitThisFrame) { + if (BeginItem(label_id)) { + if (FitThisFrame()) { + for (int i = 0; i < getter.Count; ++i) { + ImPlotPointError e = getter(i); + FitPoint(ImPlotPoint(e.X - e.Neg, e.Y)); + FitPoint(ImPlotPoint(e.X + e.Pos, e.Y)); + } + } + const ImPlotItemStyle& s = GetItemStyle(); + ImDrawList& DrawList = *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; for (int i = 0; i < getter.Count; ++i) { ImPlotPointError e = getter(i); - FitPoint(ImPlotPoint(e.X - e.Neg, e.Y)); - FitPoint(ImPlotPoint(e.X + e.Pos, e.Y)); + ImVec2 p1 = PlotToPixels(e.X - e.Neg, e.Y); + ImVec2 p2 = PlotToPixels(e.X + e.Pos, e.Y); + DrawList.AddLine(p1, p2, col, s.ErrorBarWeight); + if (rend_whisker) { + DrawList.AddLine(p1 - ImVec2(0, half_whisker), p1 + ImVec2(0, half_whisker), col, s.ErrorBarWeight); + DrawList.AddLine(p2 - ImVec2(0, half_whisker), p2 + ImVec2(0, half_whisker), col, s.ErrorBarWeight); + } } + EndItem(); } - - const ImU32 col = ImGui::GetColorU32(GetErrorBarColor()); - const bool rend_whisker = gp.Style.ErrorBarSize > 0; - const float half_whisker = gp.Style.ErrorBarSize * 0.5f; - - ImDrawList& DrawList = *ImGui::GetWindowDrawList(); - - PushPlotClipRect(); - for (int i = 0; i < getter.Count; ++i) { - ImPlotPointError e = getter(i); - ImVec2 p1 = PlotToPixels(e.X - e.Neg, e.Y); - ImVec2 p2 = PlotToPixels(e.X + e.Pos, e.Y); - DrawList.AddLine(p1, p2, col, gp.Style.ErrorBarWeight); - if (rend_whisker) { - DrawList.AddLine(p1 - ImVec2(0, half_whisker), p1 + ImVec2(0, half_whisker), col, gp.Style.ErrorBarWeight); - DrawList.AddLine(p2 - ImVec2(0, half_whisker), p2 + ImVec2(0, half_whisker), col, gp.Style.ErrorBarWeight); - } - } - PopPlotClipRect(); } // float @@ -1155,25 +1246,20 @@ inline void RenderPieSlice(ImDrawList& DrawList, const ImPlotPoint& center, doub template void PlotPieChartEx(const char** label_ids, const T* values, int count, T x, T y, T radius, bool normalize, const char* fmt, T angle0) { IM_ASSERT_USER_ERROR(GImPlot->CurrentPlot != NULL, "PlotPieChart() needs to be called between BeginPlot() and EndPlot()!"); - ImDrawList & DrawList = *ImGui::GetWindowDrawList(); - + ImDrawList & DrawList = *GetPlotDrawList(); T sum = 0; for (int i = 0; i < count; ++i) sum += values[i]; - normalize = normalize || sum > 1.0f; - ImPlotPoint center(x,y); - PushPlotClipRect(); T a0 = angle0 * 2 * IM_PI / 360.0f; T a1 = angle0 * 2 * IM_PI / 360.0f; for (int i = 0; i < count; ++i) { - ImPlotItem* item = RegisterOrGetItem(label_ids[i]); - ImU32 col = ImGui::GetColorU32(GetItemFillColor(item)); T percent = normalize ? values[i] / sum : values[i]; a1 = a0 + 2 * IM_PI * percent; - if (item->Show) { + if (BeginItem(label_ids[i])) { + ImU32 col = ImGui::GetColorU32(GetCurrentItem()->Color); if (percent < 0.5) { RenderPieSlice(DrawList, center, radius, a0, a1, col); } @@ -1181,6 +1267,7 @@ void PlotPieChartEx(const char** label_ids, const T* values, int count, T x, T y RenderPieSlice(DrawList, center, radius, a0, a0 + (a1 - a0) * 0.5f, col); RenderPieSlice(DrawList, center, radius, a0 + (a1 - a0) * 0.5f, a1, col); } + EndItem(); } a0 = a1; } @@ -1197,7 +1284,7 @@ void PlotPieChartEx(const char** label_ids, const T* values, int count, T x, T y ImVec2 size = ImGui::CalcTextSize(buffer); T angle = a0 + (a1 - a0) * 0.5f; ImVec2 pos = PlotToPixels(center.x + 0.5f * radius * cos(angle), center.y + 0.5f * radius * sin(angle)); - ImU32 col = CalcTextColor(GetItemFillColor(item)); + ImU32 col = CalcTextColor(item->Color); DrawList.AddText(pos - size * 0.5f, col, buffer); } a0 = a1; @@ -1265,29 +1352,21 @@ void RenderHeatmap(Transformer transformer, ImDrawList& DrawList, const T* value template void PlotHeatmapEx(const char* label_id, const T* values, int rows, int cols, T scale_min, T scale_max, const char* fmt, const ImPlotPoint& bounds_min, const ImPlotPoint& bounds_max) { - ImPlotContext& gp = *GImPlot; - IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "PlotHeatmap() needs to be called between BeginPlot() and EndPlot()!"); IM_ASSERT_USER_ERROR(scale_min != scale_max, "Scale values must be different!"); - ImPlotItem* item = RegisterOrGetItem(label_id); - if (!item->Show) - return; - if (gp.FitThisFrame) { - FitPoint(bounds_min); - FitPoint(bounds_max); + if (BeginItem(label_id)) { + if (FitThisFrame()) { + FitPoint(bounds_min); + FitPoint(bounds_max); + } + ImDrawList& DrawList = *GetPlotDrawList(); + switch (GetCurrentScale()) { + case ImPlotScale_LinLin: RenderHeatmap(TransformerLinLin(), DrawList, values, rows, cols, scale_min, scale_max, fmt, bounds_min, bounds_max); break; + case ImPlotScale_LogLin: RenderHeatmap(TransformerLogLin(), DrawList, values, rows, cols, scale_min, scale_max, fmt, bounds_min, bounds_max); break; + case ImPlotScale_LinLog: RenderHeatmap(TransformerLinLog(), DrawList, values, rows, cols, scale_min, scale_max, fmt, bounds_min, bounds_max); break; + case ImPlotScale_LogLog: RenderHeatmap(TransformerLogLog(), DrawList, values, rows, cols, scale_min, scale_max, fmt, bounds_min, bounds_max); break; + } + EndItem(); } - ImDrawList& DrawList = *ImGui::GetWindowDrawList(); - ImGui::PushClipRect(gp.BB_Plot.Min, gp.BB_Plot.Max, true); - ImPlotState* plot = gp.CurrentPlot; - int y_axis = plot->CurrentYAxis; - if (ImHasFlag(plot->XAxis.Flags, ImPlotAxisFlags_LogScale) && ImHasFlag(plot->YAxis[y_axis].Flags, ImPlotAxisFlags_LogScale)) - RenderHeatmap(TransformerLogLog(y_axis), DrawList, values, rows, cols, scale_min, scale_max, fmt, bounds_min, bounds_max); - else if (ImHasFlag(plot->XAxis.Flags, ImPlotAxisFlags_LogScale)) - RenderHeatmap(TransformerLogLin(y_axis), DrawList, values, rows, cols, scale_min, scale_max, fmt, bounds_min, bounds_max); - else if (ImHasFlag(plot->YAxis[y_axis].Flags, ImPlotAxisFlags_LogScale)) - RenderHeatmap(TransformerLinLog(y_axis), DrawList, values, rows, cols, scale_min, scale_max, fmt, bounds_min, bounds_max); - else - RenderHeatmap(TransformerLinLin(y_axis), DrawList, values, rows, cols, scale_min, scale_max, fmt, bounds_min, bounds_max); - ImGui::PopClipRect(); } // float @@ -1304,68 +1383,62 @@ void PlotHeatmap(const char* label_id, const double* values, int rows, int cols, // PLOT DIGITAL //----------------------------------------------------------------------------- +// TODO: Make this behave like all the other plot types + template -inline void PlotDigitalEx(const char* label_id, Getter getter) -{ - ImPlotContext& gp = *GImPlot; - IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "PlotDigital() needs to be called between BeginPlot() and EndPlot()!"); - - ImPlotItem* item = RegisterOrGetItem(label_id); - if (!item->Show) - return; - TryRecolorItem(item, ImPlotCol_Line); - - // render digital signals as "pixel bases" rectangles - PushPlotClipRect(); - if (getter.Count > 1 && WillLineRender()) { - ImDrawList & DrawList = *ImGui::GetWindowDrawList(); - const float line_weight = item->Highlight ? gp.Style.LineWeight * 2 : gp.Style.LineWeight; - const int y_axis = gp.CurrentPlot->CurrentYAxis; - int pixYMax = 0; - ImPlotPoint itemData1 = getter(0); - for (int i = 0; i < getter.Count; ++i) { - ImPlotPoint itemData2 = getter(i); - if (NanOrInf(itemData1.y)) { +inline void PlotDigitalEx(const char* label_id, Getter getter) { + if (BeginItem(label_id, ImPlotCol_Fill)) { + ImPlotContext& gp = *GImPlot; + ImDrawList& DrawList = *GetPlotDrawList(); + const ImPlotItemStyle& s = GetItemStyle(); + if (getter.Count > 1 && s.RenderFill) { + const int y_axis = GetCurrentYAxis(); + int pixYMax = 0; + ImPlotPoint itemData1 = getter(0); + for (int i = 0; i < getter.Count; ++i) { + ImPlotPoint itemData2 = getter(i); + if (NanOrInf(itemData1.y)) { + itemData1 = itemData2; + continue; + } + if (NanOrInf(itemData2.y)) itemData2.y = ConstrainNan(ConstrainInf(itemData2.y)); + int pixY_0 = (int)(s.LineWeight); + itemData1.y = ImMax(0.0, itemData1.y); + float pixY_1_float = s.DigitalBitHeight * (float)itemData1.y; + int pixY_1 = (int)(pixY_1_float); //allow only positive values + int pixY_chPosOffset = (int)(ImMax(s.DigitalBitHeight, pixY_1_float) + s.DigitalBitGap); + pixYMax = ImMax(pixYMax, pixY_chPosOffset); + ImVec2 pMin = PlotToPixels(itemData1); + ImVec2 pMax = PlotToPixels(itemData2); + int pixY_Offset = 20; //20 pixel from bottom due to mouse cursor label + pMin.y = (gp.PixelRange[y_axis].Min.y) + ((-gp.DigitalPlotOffset) - pixY_Offset); + pMax.y = (gp.PixelRange[y_axis].Min.y) + ((-gp.DigitalPlotOffset) - pixY_0 - pixY_1 - pixY_Offset); + //plot only one rectangle for same digital state + while (((i+2) < getter.Count) && (itemData1.y == itemData2.y)) { + const int in = (i + 1); + itemData2 = getter(in); + if (NanOrInf(itemData2.y)) break; + pMax.x = PlotToPixels(itemData2).x; + i++; + } + //do not extend plot outside plot range + if (pMin.x < gp.PixelRange[y_axis].Min.x) pMin.x = gp.PixelRange[y_axis].Min.x; + if (pMax.x < gp.PixelRange[y_axis].Min.x) pMax.x = gp.PixelRange[y_axis].Min.x; + if (pMin.x > gp.PixelRange[y_axis].Max.x) pMin.x = gp.PixelRange[y_axis].Max.x; + if (pMax.x > gp.PixelRange[y_axis].Max.x) pMax.x = gp.PixelRange[y_axis].Max.x; + //plot a rectangle that extends up to x2 with y1 height + if ((pMax.x > pMin.x) && (gp.BB_Plot.Contains(pMin) || gp.BB_Plot.Contains(pMax))) { + // ImVec4 colAlpha = item->Color; + // colAlpha.w = item->Highlight ? 1.0f : 0.9f; + DrawList.AddRectFilled(pMin, pMax, ImGui::GetColorU32(s.Colors[ImPlotCol_Fill])); + } itemData1 = itemData2; - continue; } - if (NanOrInf(itemData2.y)) itemData2.y = ConstrainNan(ConstrainInf(itemData2.y)); - int pixY_0 = (int)(line_weight); - itemData1.y = ImMax(0.0, itemData1.y); - float pixY_1_float = gp.Style.DigitalBitHeight * (float)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 = PlotToPixels(itemData1); - ImVec2 pMax = PlotToPixels(itemData2); - int pixY_Offset = 20; //20 pixel from bottom due to mouse cursor label - pMin.y = (gp.PixelRange[y_axis].Min.y) + ((-gp.DigitalPlotOffset) - pixY_Offset); - pMax.y = (gp.PixelRange[y_axis].Min.y) + ((-gp.DigitalPlotOffset) - pixY_0 - pixY_1 - pixY_Offset); - //plot only one rectangle for same digital state - while (((i+2) < getter.Count) && (itemData1.y == itemData2.y)) { - const int in = (i + 1); - itemData2 = getter(in); - if (NanOrInf(itemData2.y)) break; - pMax.x = PlotToPixels(itemData2).x; - i++; - } - //do not extend plot outside plot range - if (pMin.x < gp.PixelRange[y_axis].Min.x) pMin.x = gp.PixelRange[y_axis].Min.x; - if (pMax.x < gp.PixelRange[y_axis].Min.x) pMax.x = gp.PixelRange[y_axis].Min.x; - if (pMin.x > gp.PixelRange[y_axis].Max.x) pMin.x = gp.PixelRange[y_axis].Max.x; - if (pMax.x > gp.PixelRange[y_axis].Max.x) pMax.x = gp.PixelRange[y_axis].Max.x; - //plot a rectangle that extends up to x2 with y1 height - if ((pMax.x > pMin.x) && (gp.BB_Plot.Contains(pMin) || gp.BB_Plot.Contains(pMax))) { - ImVec4 colAlpha = item->Color; - colAlpha.w = item->Highlight ? 1.0f : 0.9f; - DrawList.AddRectFilled(pMin, pMax, ImGui::GetColorU32(colAlpha)); - } - itemData1 = itemData2; + gp.DigitalPlotItemCnt++; + gp.DigitalPlotOffset += pixYMax; } - gp.DigitalPlotItemCnt++; - gp.DigitalPlotOffset += pixYMax; + EndItem(); } - PopPlotClipRect(); } // float @@ -1391,39 +1464,26 @@ void PlotDigital(const char* label_id, ImPlotPoint (*getter_func)(void* data, in //----------------------------------------------------------------------------- template void PlotRectsEx(const char* label_id, Getter getter) { - ImPlotContext& gp = *GImPlot; - IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "PlotRects() needs to be called between BeginPlot() and EndPlot()!"); - - ImPlotItem* item = RegisterOrGetItem(label_id); - if (!item->Show) - return; - TryRecolorItem(item, ImPlotCol_Fill); - - if (!WillFillRender()) - return; - - if (gp.FitThisFrame) { - for (int i = 0; i < getter.Count; ++i) { - ImPlotPoint p = getter(i); - FitPoint(p); + if (BeginItem(label_id, ImPlotCol_Fill)) { + if (FitThisFrame()) { + for (int i = 0; i < getter.Count; ++i) { + ImPlotPoint p = getter(i); + FitPoint(p); + } } + const ImPlotItemStyle& s = GetItemStyle(); + if (s.RenderFill) { + ImDrawList& DrawList = *GetPlotDrawList(); + ImU32 col = ImGui::GetColorU32(s.Colors[ImPlotCol_Fill]); + switch (GetCurrentScale()) { + case ImPlotScale_LinLin: RenderPrimitives(RectRenderer(getter, TransformerLinLin(), col), DrawList); break; + case ImPlotScale_LogLin: RenderPrimitives(RectRenderer(getter, TransformerLogLin(), col), DrawList); break; + case ImPlotScale_LinLog: RenderPrimitives(RectRenderer(getter, TransformerLinLog(), col), DrawList); break; + case ImPlotScale_LogLog: RenderPrimitives(RectRenderer(getter, TransformerLogLog(), col), DrawList); break; + } + } + EndItem(); } - - ImDrawList & DrawList = *ImGui::GetWindowDrawList(); - ImPlotState* plot = gp.CurrentPlot; - const int y_axis = plot->CurrentYAxis; - ImU32 col = ImGui::GetColorU32(GetItemFillColor(item)); - - PushPlotClipRect(); - if (ImHasFlag(plot->XAxis.Flags, ImPlotAxisFlags_LogScale) && ImHasFlag(plot->YAxis[y_axis].Flags, ImPlotAxisFlags_LogScale)) - RenderPrimitives(RectRenderer(getter, TransformerLogLog(y_axis), col), DrawList); - else if (ImHasFlag(plot->XAxis.Flags, ImPlotAxisFlags_LogScale)) - RenderPrimitives(RectRenderer(getter, TransformerLogLin(y_axis), col), DrawList); - else if (ImHasFlag(plot->YAxis[y_axis].Flags, ImPlotAxisFlags_LogScale)) - RenderPrimitives(RectRenderer(getter, TransformerLinLog(y_axis), col), DrawList); - else - RenderPrimitives(RectRenderer(getter, TransformerLinLin(y_axis), col), DrawList); - PopPlotClipRect(); } // float @@ -1456,9 +1516,9 @@ void PlotText(const char* text, float x, float y, bool vertical, const ImVec2& p // double void PlotText(const char* text, double x, double y, bool vertical, const ImVec2& pixel_offset) { IM_ASSERT_USER_ERROR(GImPlot->CurrentPlot != NULL, "PlotText() needs to be called between BeginPlot() and EndPlot()!"); - ImDrawList & DrawList = *ImGui::GetWindowDrawList(); + ImDrawList & DrawList = *GetPlotDrawList(); PushPlotClipRect(); - ImU32 colTxt = ImGui::GetColorU32(ImGuiCol_Text); + ImU32 colTxt = GetStyleColorU32(ImPlotCol_InlayText); if (vertical) { ImVec2 ctr = CalcTextSizeVertical(text) * 0.5f; ImVec2 pos = PlotToPixels(ImPlotPoint(x,y)) + ImVec2(-ctr.x, ctr.y) + pixel_offset;