diff --git a/implot.cpp b/implot.cpp index 85bc6f3..efa8e10 100644 --- a/implot.cpp +++ b/implot.cpp @@ -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 = ImPlotNextItemStyle(); // reset items count ctx->VisibleItemCount = 0; // reset legend items @@ -1731,6 +1732,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()!"); @@ -2316,7 +2321,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); @@ -2353,7 +2358,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) @@ -2374,7 +2379,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."); @@ -2506,31 +2511,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) { @@ -2539,10 +2544,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); @@ -2571,11 +2576,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); @@ -2603,11 +2608,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 a129afc..303c300 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 style color should be deduced automatically from ImGui style or ImPlot colormaps. +#define IMPLOT_AUTO_COL ImVec4(0,0,0,-1) //----------------------------------------------------------------------------- // Forward Declarations and Basic Types @@ -381,12 +390,12 @@ 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 @@ -403,13 +412,13 @@ 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); @@ -417,9 +426,6 @@ bool IsLegendEntryHovered(const char* label_id); // Plot and Item Styling and Colormaps //----------------------------------------------------------------------------- -// 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) - // Provides access to plot style structure for permanant modifications to colors, sizes, etc. ImPlotStyle& GetStyle(); @@ -432,9 +438,17 @@ void StyleColorsDark(ImPlotStyle* dst = NULL); // Style colors for ImGui "Light". void StyleColorsLight(ImPlotStyle* dst = NULL); +// Set the line color and weight for the next item only. +void SetNextLineStyle(const ImVec4& col, float weight = IMPLOT_AUTO); +// Set the fill color for the next item only. +void SetNextFillStyle(const ImVec4& col, float alpha_mod = IMPLOT_AUTO); +// Set the marker style for the next item only. +void SetNextMarkerStyle(ImPlotMarker marker, const ImVec4& fill = IMPLOT_AUTO_COL, float size = IMPLOT_AUTO, const ImVec4& outline = IMPLOT_AUTO_COL, float weight = IMPLOT_AUTO); +// Set the error bar style for the next item only. +void SetNextErrorBarStyle(const ImVec4& col, float size = IMPLOT_AUTO, float weight = IMPLOT_AUTO); + // 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. void PopStyleColor(int count = 1); @@ -448,12 +462,6 @@ void PushStyleVar(ImPlotStyleVar idx, const ImVec2& val); // Undo temporary style modification. void PopStyleVar(int count = 1); -void SetNextItemColor(ImPlotCol idx, const ImVec4& col); -void SetNextItemColor(ImPlotCol idx, ImU32 col); -void SetNextItemColorV(int count, ...); - - - // 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! @@ -474,6 +482,7 @@ ImVec4 LerpColormap(float t); // Returns the next unused colormap color and advances the colormap. Can be used to skip colors if desired. ImVec4 NextColormapColor(); +// Retusn the null terminated string name for a ImPlotCol const char* GetStyleColorName(ImPlotCol color); // Returns a null terminated string name for a built-in colormap const char* GetColormapName(ImPlotColormap colormap); @@ -495,6 +504,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..70c74e4 100644 --- a/implot_demo.cpp +++ b/implot_demo.cpp @@ -238,14 +238,11 @@ void ShowDemoWindow(bool* p_open) { } 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(); } } @@ -1124,10 +1121,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); diff --git a/implot_internal.h b/implot_internal.h index 25b0cde..4161f42 100644 --- a/implot_internal.h +++ b/implot_internal.h @@ -373,8 +373,8 @@ struct ImPlotNextPlotData }; // Temporary data storage for upcoming item -struct ImPlotNextItemData { - ImVec4 Colors[5]; +struct ImPlotNextItemStyle { + ImVec4 Colors[5]; // ImPlotCol_Line, ImPlotCol_Fill, ImPlotCol_MarkerOutline, ImPlotCol_MarkerFill, ImPlotCol_ErrorBar float LineWeight; ImPlotMarker Marker; float MarkerSize; @@ -384,12 +384,16 @@ struct ImPlotNextItemData { float ErrorBarWeight; float DigitalBitHeight; float DigitalBitGap; - ImPlotNextItemData() { + bool RenderLine; + bool RenderFill; + bool RenderMarkerLine; + bool RenderMarkerFill; + ImPlotNextItemStyle() { for (int i = 0; i < 5; ++i) - Colors[i] = IMPLOT_COL_AUTO; + Colors[i] = IMPLOT_AUTO_COL; LineWeight = MarkerWeight = FillAlpha = ErrorBarSize = - ErrorBarSize = ErrorBarWeight = DigitalBitHeight = DigitalBitGap = -1; - Marker = -1; + ErrorBarSize = ErrorBarWeight = DigitalBitHeight = DigitalBitGap = IMPLOT_AUTO; + Marker = IMPLOT_AUTO; } }; @@ -460,7 +464,7 @@ struct ImPlotContext { int DigitalPlotItemCnt; int DigitalPlotOffset; ImPlotNextPlotData NextPlotData; - ImPlotNextItemData NextItemData; + ImPlotNextItemStyle NextItemStyle; ImPlotInputMap InputMap; ImPlotPoint MousePos[IMPLOT_Y_AXES]; }; @@ -505,7 +509,7 @@ inline int GetCurrentYAxis() { return GImPlot->CurrentPlot->CurrentYAxis; } inline ImPlotScale GetCurrentScale() { return GImPlot->Scales[GetCurrentYAxis()]; } // Begins a new item. Returns false if the item should not be plotted. -bool BeginItem(const char* label_id); +bool BeginItem(const char* label_id, ImPlotCol recolor_from = -1); // Ends an item (call only if BeginItem returns true) void EndItem(); @@ -523,7 +527,7 @@ ImPlotItem* GetCurrentItem(); void BustItemCache(); // Get styling data for next item (call between Begin/EndItem) -const ImPlotNextItemData& GetNextItemData(); +inline const ImPlotNextItemStyle& 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) { @@ -609,8 +613,10 @@ 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 diff --git a/implot_items.cpp b/implot_items.cpp index e41c303..8df8aff 100644 --- a/implot_items.cpp +++ b/implot_items.cpp @@ -105,18 +105,56 @@ void BustItemCache() { } // Begins a new item. Returns false if the item should not be plotted. -bool BeginItem(const char* label_id) { +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.NextItemData = ImPlotNextItemData(); + gp.NextItemStyle = ImPlotNextItemStyle(); return false; } else { // set current item gp.CurrentItem = item; - // stage next item data + ImPlotNextItemStyle& 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 : GImPlot->Style.Colors[ImPlotCol_Line] ) : s.Colors[ImPlotCol_Line]; + s.Colors[ImPlotCol_Fill] = IsColorAuto(s.Colors[ImPlotCol_Fill]) ? ( IsColorAuto(ImPlotCol_Fill) ? item->Color : GImPlot->Style.Colors[ImPlotCol_Fill] ) : s.Colors[ImPlotCol_Fill]; + s.Colors[ImPlotCol_MarkerOutline] = IsColorAuto(s.Colors[ImPlotCol_MarkerOutline]) ? ( IsColorAuto(ImPlotCol_MarkerOutline) ? s.Colors[ImPlotCol_Line] : GImPlot->Style.Colors[ImPlotCol_MarkerOutline] ) : s.Colors[ImPlotCol_MarkerOutline]; + s.Colors[ImPlotCol_MarkerFill] = IsColorAuto(s.Colors[ImPlotCol_MarkerFill]) ? ( IsColorAuto(ImPlotCol_MarkerFill) ? s.Colors[ImPlotCol_Line] : GImPlot->Style.Colors[ImPlotCol_MarkerFill] ) : s.Colors[ImPlotCol_MarkerFill]; + s.Colors[ImPlotCol_ErrorBar] = IsColorAuto(s.Colors[ImPlotCol_Line]) ? ( 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; + // apply highlight mods + if (item->Highlight) { + s.LineWeight *= 2; + } + // 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; } } @@ -124,12 +162,43 @@ bool BeginItem(const char* label_id) { // Ends an item (call only if BeginItem returns true) void EndItem() { ImPlotContext& gp = *GImPlot; + // pop rendering clip rect + PopPlotClipRect(); // reset next item data - gp.NextItemData = ImPlotNextItemData(); + gp.NextItemStyle = ImPlotNextItemStyle(); // 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, const ImVec4& fill, float size, const ImVec4& outline, float weight) { + 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 //----------------------------------------------------------------------------- @@ -288,6 +357,7 @@ struct GetterError { //----------------------------------------------------------------------------- // Transforms convert points in plot space (i.e. ImPlotPoint) to pixel space (i.e. ImVec2) +// TODO: Cache transformation variables for // Transforms points for linear x and linear y space struct TransformerLinLin { @@ -669,7 +739,7 @@ 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) { +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) = { NULL, RenderMarkerCircle, @@ -687,7 +757,7 @@ inline void RenderMarkers(Getter getter, Transformer transformer, ImDrawList& Dr 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); + marker_table[marker](DrawList, c, size, rend_mk_line, col_mk_line, rend_mk_fill, col_mk_fill, weight); } } @@ -696,51 +766,39 @@ inline void RenderMarkers(Getter getter, Transformer transformer, ImDrawList& Dr //----------------------------------------------------------------------------- template -inline void PlotEx(const char* label_id, Getter getter) -{ +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); + if (BeginItem(label_id, ImPlotCol_Line)) { + if (gp.FitThisFrame) { + for (int i = 0; i < getter.Count; ++i) { + ImPlotPoint p = getter(i); + FitPoint(p); + } } - } - - ImDrawList& DrawList = *ImGui::GetWindowDrawList(); - PushPlotClipRect(); - // render line - if (getter.Count > 1 && WillLineRender()) { - const ImU32 col_line = ImGui::GetColorU32(GetLineColor(item)); - const float line_weight = item->Highlight ? gp.Style.LineWeight * 2 : gp.Style.LineWeight; - switch (GetCurrentScale()) { - case ImPlotScale_LinLin: RenderLineStrip(getter, TransformerLinLin(), DrawList, line_weight, col_line); break; - case ImPlotScale_LogLin: RenderLineStrip(getter, TransformerLogLin(), DrawList, line_weight, col_line); break; - case ImPlotScale_LinLog: RenderLineStrip(getter, TransformerLinLog(), DrawList, line_weight, col_line); break; - case ImPlotScale_LogLog: RenderLineStrip(getter, TransformerLogLog(), DrawList, line_weight, col_line); break; + const ImPlotNextItemStyle& 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 (gp.Style.Marker != ImPlotMarker_None) { - const bool rend_line = WillMarkerOutlineRender(); - const bool rend_fill = WillMarkerFillRender(); - const ImU32 col_line = ImGui::GetColorU32(GetMarkerOutlineColor(item)); - const ImU32 col_fill = ImGui::GetColorU32(GetMarkerFillColor(item)); - switch (GetCurrentScale()) { - case ImPlotScale_LinLin: RenderMarkers(getter, TransformerLinLin(), DrawList, rend_line, col_line, rend_fill, col_fill); break; - case ImPlotScale_LogLin: RenderMarkers(getter, TransformerLogLin(), DrawList, rend_line, col_line, rend_fill, col_fill); break; - case ImPlotScale_LinLog: RenderMarkers(getter, TransformerLinLog(), DrawList, rend_line, col_line, rend_fill, col_fill); break; - case ImPlotScale_LogLog: RenderMarkers(getter, TransformerLogLog(), DrawList, rend_line, col_line, rend_fill, col_fill); 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(); } - PopPlotClipRect(); } // float @@ -849,36 +907,28 @@ 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 (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); + } } + const ImPlotNextItemStyle& 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(); - ImU32 col = ImGui::GetColorU32(GetItemFillColor(item)); - PushPlotClipRect(); - 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; - } - PopPlotClipRect(); } // float @@ -957,7 +1007,7 @@ void PlotBarsEx(const char* label_id, Getter getter, TWidth width) { if (rend_fill && col_line == col_fill) rend_line = false; - ImDrawList & DrawList = *ImGui::GetWindowDrawList(); + ImDrawList& DrawList = *GetPlotDrawList(); PushPlotClipRect(); for (int i = 0; i < getter.Count; ++i) { ImPlotPoint p = getter(i); @@ -1035,7 +1085,7 @@ void PlotBarsHEx(const char* label_id, Getter getter, THeight height) { rend_line = false; PushPlotClipRect(); - ImDrawList & DrawList = *ImGui::GetWindowDrawList(); + ImDrawList& DrawList = *GetPlotDrawList(); for (int i = 0; i < getter.Count; ++i) { ImPlotPoint p = getter(i); if (p.x == 0) @@ -1104,7 +1154,7 @@ void PlotErrorBarsEx(const char* label_id, Getter getter) { const bool rend_whisker = gp.Style.ErrorBarSize > 0; const float half_whisker = gp.Style.ErrorBarSize * 0.5f; - ImDrawList & DrawList = *ImGui::GetWindowDrawList(); + ImDrawList & DrawList = *GetPlotDrawList(); PushPlotClipRect(); for (int i = 0; i < getter.Count; ++i) { @@ -1168,7 +1218,7 @@ void PlotErrorBarsHEx(const char* label_id, Getter getter) { const bool rend_whisker = gp.Style.ErrorBarSize > 0; const float half_whisker = gp.Style.ErrorBarSize * 0.5f; - ImDrawList& DrawList = *ImGui::GetWindowDrawList(); + ImDrawList& DrawList = *GetPlotDrawList(); PushPlotClipRect(); for (int i = 0; i < getter.Count; ++i) { @@ -1226,7 +1276,7 @@ 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) @@ -1346,7 +1396,7 @@ void PlotHeatmapEx(const char* label_id, const T* values, int rows, int cols, T FitPoint(bounds_min); FitPoint(bounds_max); } - ImDrawList& DrawList = *ImGui::GetWindowDrawList(); + ImDrawList& DrawList = *GetPlotDrawList(); ImGui::PushClipRect(gp.BB_Plot.Min, gp.BB_Plot.Max, true); switch (GetCurrentScale()) { case ImPlotScale_LinLin: RenderHeatmap(TransformerLinLin(), DrawList, values, rows, cols, scale_min, scale_max, fmt, bounds_min, bounds_max); break; @@ -1385,7 +1435,7 @@ inline void PlotDigitalEx(const char* label_id, Getter getter) // render digital signals as "pixel bases" rectangles PushPlotClipRect(); if (getter.Count > 1 && WillLineRender()) { - ImDrawList & DrawList = *ImGui::GetWindowDrawList(); + ImDrawList & DrawList = *GetPlotDrawList(); const float line_weight = item->Highlight ? gp.Style.LineWeight * 2 : gp.Style.LineWeight; const int y_axis = gp.CurrentPlot->CurrentYAxis; int pixYMax = 0; @@ -1476,7 +1526,7 @@ void PlotRectsEx(const char* label_id, Getter getter) { } } - ImDrawList & DrawList = *ImGui::GetWindowDrawList(); + ImDrawList & DrawList = *GetPlotDrawList(); ImU32 col = ImGui::GetColorU32(GetItemFillColor(item)); PushPlotClipRect(); switch (GetCurrentScale()) { @@ -1518,7 +1568,7 @@ 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); if (vertical) {