diff --git a/implot.cpp b/implot.cpp index 209f5fe..b32d064 100644 --- a/implot.cpp +++ b/implot.cpp @@ -231,7 +231,7 @@ void Reset(ImPlotContext* ctx) { ctx->FitX = false; ctx->ExtentsX.Min = HUGE_VAL; ctx->ExtentsX.Max = -HUGE_VAL; - for (int i = 0; i < MAX_Y_AXES; i++) { + for (int i = 0; i < IMPLOT_Y_AXES; i++) { ctx->ExtentsY[i].Min = HUGE_VAL; ctx->ExtentsY[i].Max = -HUGE_VAL; ctx->FitY[i] = false; @@ -278,7 +278,7 @@ void FitPoint(const ImPlotPoint& p) { void UpdateTransformCache() { ImPlotContext& gp = *GImPlot; // get pixels for transforms - for (int i = 0; i < MAX_Y_AXES; i++) { + for (int i = 0; i < IMPLOT_Y_AXES; i++) { gp.PixelRange[i] = ImRect(ImHasFlag(gp.CurrentPlot->XAxis.Flags, ImPlotAxisFlags_Invert) ? gp.BB_Plot.Max.x : gp.BB_Plot.Min.x, 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, @@ -287,7 +287,7 @@ void UpdateTransformCache() { 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 < MAX_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(); @@ -416,7 +416,7 @@ void AddDefaultTicks(const ImPlotRange& range, int nMajor, int nMinor, bool logs double major2 = ImPow(10, (double)(e + 1)); double interval = (major2 - major1) / 9; if (major1 >= (range.Min - DBL_EPSILON) && major1 <= (range.Max + DBL_EPSILON)) - out.push_back(ImPlotTick(major1, true)); + out.push_back(ImPlotTick(major1, true, true)); for (int i = 1; i < 9; ++i) { double minor = major1 + i * interval; if (minor >= (range.Min - DBL_EPSILON) && minor <= (range.Max + DBL_EPSILON)) @@ -425,17 +425,17 @@ void AddDefaultTicks(const ImPlotRange& range, int nMajor, int nMinor, bool logs } } else { - const double nice_range = NiceNum(range.Size() * 0.99, 0); - const double interval = NiceNum(nice_range / (nMajor - 1), 1); + const double nice_range = NiceNum(range.Size() * 0.99, false); + const double interval = NiceNum(nice_range / (nMajor - 1), true); 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 (major >= range.Min && major <= range.Max) - out.push_back(ImPlotTick(major, true)); + if (range.Contains(major)) + out.push_back(ImPlotTick(major, true, true)); for (int i = 1; i < nMinor; ++i) { double minor = major + i * interval / nMinor; - if (minor >= range.Min && minor <= range.Max) - out.push_back(ImPlotTick(minor, false)); + if (range.Contains(minor)) + out.push_back(ImPlotTick(minor, false, true)); } } } @@ -443,11 +443,11 @@ void AddDefaultTicks(const ImPlotRange& range, int nMajor, int nMinor, bool logs void AddCustomTicks(const double* values, const char** labels, int n, ImVector& ticks, ImGuiTextBuffer& buffer) { for (int i = 0; i < n; ++i) { - ImPlotTick tick(values[i],false); - tick.TextOffset = buffer.size(); + ImPlotTick tick(values[i],false, true); + tick.BufferOffset = buffer.size(); if (labels != NULL) { buffer.append(labels[i], labels[i] + strlen(labels[i]) + 1); - tick.Size = ImGui::CalcTextSize(labels[i]); + tick.LabelSize = ImGui::CalcTextSize(labels[i]); tick.Labeled = true; } ticks.push_back(tick); @@ -458,26 +458,40 @@ void LabelTicks(ImVector &ticks, bool scientific, ImGuiTextBuffer& b char temp[32]; for (int t = 0; t < ticks.Size; t++) { ImPlotTick *tk = &ticks[t]; - if (tk->RenderLabel && !tk->Labeled) { - tk->TextOffset = buffer.size(); + if (tk->ShowLabel && !tk->Labeled) { + tk->BufferOffset = buffer.size(); if (scientific) sprintf(temp, "%.0e", tk->PlotPos); else sprintf(temp, "%.10g", tk->PlotPos); buffer.append(temp, temp + strlen(temp) + 1); - tk->Size = ImGui::CalcTextSize(buffer.Buf.Data + tk->TextOffset); + tk->LabelSize = ImGui::CalcTextSize(buffer.Buf.Data + tk->BufferOffset); tk->Labeled = true; } } } -float MaxTickLabelWidth(ImVector& ticks) { +float MaxTickLabelWidth(const ImVector& ticks) { float w = 0; for (int i = 0; i < ticks.Size; ++i) - w = ticks[i].Size.x > w ? ticks[i].Size.x : w; + w = (ticks[i].ShowLabel && ticks[i].LabelSize.x > w) ? ticks[i].LabelSize.x : w; return w; } +float SumTickLabelWidth(const ImVector& ticks) { + float sum = 0; + for (int i = 0; i < ticks.Size; ++i) + sum += ticks[i].ShowLabel ? ticks[i].LabelSize.x : 0; + return sum; +} + +float SumTickLabelHeight(const ImVector& ticks) { + float sum = 0; + for (int i = 0; i < ticks.Size; ++i) + sum += ticks[i].ShowLabel ? ticks[i].LabelSize.y : 0; + return sum; +} + class YPadCalculator { public: YPadCalculator(const ImPlotAxisState* axis_states, const float* max_label_widths, float txt_off) @@ -512,10 +526,11 @@ class YPadCalculator { void UpdateAxisColor(int axis_flag, ImPlotAxisColor* col) { ImPlotContext& gp = *GImPlot; - const ImVec4 col_Axis = gp.Style.Colors[axis_flag].w == -1 ? ImGui::GetStyle().Colors[ImGuiCol_Text] * ImVec4(1, 1, 1, 0.25f) : gp.Style.Colors[axis_flag]; - col->Major = ImGui::GetColorU32(col_Axis); - col->Minor = ImGui::GetColorU32(col_Axis * ImVec4(1, 1, 1, 0.25f)); - col->Txt = ImGui::GetColorU32(ImVec4(col_Axis.x, col_Axis.y, col_Axis.z, 1)); + const ImVec4 col_axis = gp.Style.Colors[axis_flag].w == -1 ? ImGui::GetStyle().Colors[ImGuiCol_Text] * ImVec4(1, 1, 1, 0.25f) : gp.Style.Colors[axis_flag]; + col->Major = ImGui::GetColorU32(col_axis); + col->Minor = ImGui::GetColorU32(col_axis * ImVec4(1, 1, 1, 0.25f)); + col->MajTxt = ImGui::GetColorU32(ImVec4(col_axis.x, col_axis.y, col_axis.z, 1)); + col->MinTxt = ImGui::GetColorU32(ImVec4(col_axis.x, col_axis.y, col_axis.z, 0.8f)); } //----------------------------------------------------------------------------- @@ -541,7 +556,7 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons const ImGuiIO & IO = ImGui::GetIO(); bool just_created = gp.Plots.GetByKey(ID) == NULL; - gp.CurrentPlot = gp.Plots.GetOrAddByKey(ID); + gp.CurrentPlot = gp.Plots.GetOrAddByKey(ID); ImPlotState &plot = *gp.CurrentPlot; plot.CurrentYAxis = 0; @@ -573,10 +588,8 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons plot.YAxis[2].PreviousFlags = y3_flags; // capture scroll with a child region - const float default_w = 400; - const float default_h = 300; if (!ImHasFlag(plot.Flags, ImPlotFlags_NoChild)) { - ImGui::BeginChild(title, ImVec2(size.x == 0 ? default_w : size.x, size.y == 0 ? default_h : size.y)); + ImGui::BeginChild(title, ImVec2(size.x == 0 ? IMPLOT_DEFAULT_W : size.x, size.y == 0 ? IMPLOT_DEFAULT_H : size.y)); Window = ImGui::GetCurrentWindow(); Window->ScrollMax.y = 1.0f; gp.ChildWindowMade = true; @@ -590,16 +603,14 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons // NextPlotData ----------------------------------------------------------- if (gp.NextPlotData.HasXRange) { - if (just_created || gp.NextPlotData.XRangeCond == ImGuiCond_Always) - { + if (just_created || gp.NextPlotData.XRangeCond == ImGuiCond_Always) { plot.XAxis.Range = gp.NextPlotData.X; } } - for (int i = 0; i < MAX_Y_AXES; i++) { + for (int i = 0; i < IMPLOT_Y_AXES; i++) { if (gp.NextPlotData.HasYRange[i]) { - if (just_created || gp.NextPlotData.YRangeCond[i] == ImGuiCond_Always) - { + if (just_created || gp.NextPlotData.YRangeCond[i] == ImGuiCond_Always) { plot.YAxis[i].Range = gp.NextPlotData.Y[i]; } } @@ -609,9 +620,9 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons gp.X = ImPlotAxisState(&plot.XAxis, gp.NextPlotData.HasXRange, gp.NextPlotData.XRangeCond, true, 0); gp.Y[0] = ImPlotAxisState(&plot.YAxis[0], gp.NextPlotData.HasYRange[0], gp.NextPlotData.YRangeCond[0], true, 0); gp.Y[1] = ImPlotAxisState(&plot.YAxis[1], gp.NextPlotData.HasYRange[1], gp.NextPlotData.YRangeCond[1], - ImHasFlag(plot.Flags, ImPlotFlags_YAxis2), gp.Y[0].PresentSoFar); + ImHasFlag(plot.Flags, ImPlotFlags_YAxis2), gp.Y[0].PresentSoFar); gp.Y[2] = ImPlotAxisState(&plot.YAxis[2], gp.NextPlotData.HasYRange[2], gp.NextPlotData.YRangeCond[2], - ImHasFlag(plot.Flags, ImPlotFlags_YAxis3), gp.Y[1].PresentSoFar); + ImHasFlag(plot.Flags, ImPlotFlags_YAxis3), gp.Y[1].PresentSoFar); gp.LockPlot = gp.X.Lock && gp.Y[0].Lock && gp.Y[1].Lock && gp.Y[2].Lock; @@ -619,7 +630,7 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons plot.XAxis.Range.Min = ConstrainNan(ConstrainInf(plot.XAxis.Range.Min)); plot.XAxis.Range.Max = ConstrainNan(ConstrainInf(plot.XAxis.Range.Max)); - for (int i = 0; i < MAX_Y_AXES; i++) { + for (int i = 0; i < IMPLOT_Y_AXES; i++) { plot.YAxis[i].Range.Min = ConstrainNan(ConstrainInf(plot.YAxis[i].Range.Min)); plot.YAxis[i].Range.Max = ConstrainNan(ConstrainInf(plot.YAxis[i].Range.Max)); } @@ -628,7 +639,7 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons plot.XAxis.Range.Min = ConstrainLog(plot.XAxis.Range.Min); if (ImHasFlag(plot.XAxis.Flags, ImPlotAxisFlags_LogScale)) plot.XAxis.Range.Max = ConstrainLog(plot.XAxis.Range.Max); - for (int i = 0; i < MAX_Y_AXES; i++) { + for (int i = 0; i < IMPLOT_Y_AXES; i++) { if (ImHasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_LogScale)) plot.YAxis[i].Range.Min = ConstrainLog(plot.YAxis[i].Range.Min); if (ImHasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_LogScale)) @@ -637,7 +648,7 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons if (plot.XAxis.Range.Max <= plot.XAxis.Range.Min) plot.XAxis.Range.Max = plot.XAxis.Range.Min + DBL_EPSILON; - for (int i = 0; i < MAX_Y_AXES; i++) { + for (int i = 0; i < IMPLOT_Y_AXES; i++) { if (plot.YAxis[i].Range.Max <= plot.YAxis[i].Range.Min) plot.YAxis[i].Range.Max = plot.YAxis[i].Range.Min + DBL_EPSILON; } @@ -663,7 +674,11 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons // BB AND HOVER ----------------------------------------------------------- // frame - const ImVec2 frame_size = ImGui::CalcItemSize(size, default_w, default_h); + ImVec2 frame_size = ImGui::CalcItemSize(size, IMPLOT_DEFAULT_W, IMPLOT_DEFAULT_H); + if (frame_size.x < IMPLOT_MIN_W && size.x < 0.0f) + frame_size.x = IMPLOT_MIN_W; + if (frame_size.y < IMPLOT_MIN_H && size.y < 0.0f) + frame_size.y = IMPLOT_MIN_H; gp.BB_Frame = ImRect(Window->DC.CursorPos, Window->DC.CursorPos + frame_size); ImGui::ItemSize(gp.BB_Frame); if (!ImGui::ItemAdd(gp.BB_Frame, 0, &gp.BB_Frame)) { @@ -678,15 +693,15 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons // adaptive divisions int x_divisions = ImMax(2, (int)IM_ROUND(0.003 * gp.BB_Canvas.GetWidth())); - int y_divisions[MAX_Y_AXES]; - for (int i = 0; i < MAX_Y_AXES; i++) { + int y_divisions[IMPLOT_Y_AXES]; + for (int i = 0; i < IMPLOT_Y_AXES; i++) { y_divisions[i] = ImMax(2, (int)IM_ROUND(0.003 * gp.BB_Canvas.GetHeight())); } gp.RenderX = (ImHasFlag(plot.XAxis.Flags, ImPlotAxisFlags_GridLines) || - ImHasFlag(plot.XAxis.Flags, ImPlotAxisFlags_TickMarks) || - ImHasFlag(plot.XAxis.Flags, ImPlotAxisFlags_TickLabels)) && x_divisions > 1; - for (int i = 0; i < MAX_Y_AXES; i++) { + ImHasFlag(plot.XAxis.Flags, ImPlotAxisFlags_TickMarks) || + ImHasFlag(plot.XAxis.Flags, ImPlotAxisFlags_TickLabels)) && x_divisions > 1; + for (int i = 0; i < IMPLOT_Y_AXES; i++) { gp.RenderY[i] = gp.Y[i].Present && (ImHasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_GridLines) || @@ -695,10 +710,10 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons } // get ticks if (gp.RenderX && gp.NextPlotData.ShowDefaultTicksX) - AddDefaultTicks(plot.XAxis.Range, x_divisions, 10, ImHasFlag(plot.XAxis.Flags, ImPlotAxisFlags_LogScale), gp.XTicks); - for (int i = 0; i < MAX_Y_AXES; i++) { + AddDefaultTicks(plot.XAxis.Range, x_divisions, IMPLOT_SUB_DIV, ImHasFlag(plot.XAxis.Flags, ImPlotAxisFlags_LogScale), gp.XTicks); + for (int i = 0; i < IMPLOT_Y_AXES; i++) { if (gp.RenderY[i] && gp.NextPlotData.ShowDefaultTicksY[i]) { - AddDefaultTicks(plot.YAxis[i].Range, y_divisions[i], 10, ImHasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_LogScale), gp.YTicks[i]); + AddDefaultTicks(plot.YAxis[i].Range, y_divisions[i], IMPLOT_SUB_DIV, ImHasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_LogScale), gp.YTicks[i]); } } @@ -706,8 +721,8 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons if (ImHasFlag(plot.XAxis.Flags, ImPlotAxisFlags_TickLabels)) LabelTicks(gp.XTicks, ImHasFlag(plot.XAxis.Flags, ImPlotAxisFlags_Scientific), gp.XTickLabels); - float max_label_width[MAX_Y_AXES] = {}; - for (int i = 0; i < MAX_Y_AXES; i++) { + float max_label_width[IMPLOT_Y_AXES] = {}; + for (int i = 0; i < IMPLOT_Y_AXES; i++) { if (gp.Y[i].Present && ImHasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_TickLabels)) { LabelTicks(gp.YTicks[i], ImHasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_Scientific), gp.YTickLabels[i]); max_label_width[i] = MaxTickLabelWidth(gp.YTicks[i]); @@ -716,12 +731,11 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons // grid bb const ImVec2 title_size = ImGui::CalcTextSize(title, NULL, true); - const float txt_off = 5; const float txt_height = ImGui::GetTextLineHeight(); - const float pad_top = title_size.x > 0.0f ? txt_height + txt_off : 0; - const float pad_bot = (ImHasFlag(plot.XAxis.Flags, ImPlotAxisFlags_TickLabels) ? txt_height + txt_off : 0) + (x_label ? txt_height + txt_off : 0); - YPadCalculator y_axis_pad(gp.Y, max_label_width, txt_off); - const float pad_left = y_axis_pad(0) + (y_label ? txt_height + txt_off : 0); + const float pad_top = title_size.x > 0.0f ? txt_height + IMPLOT_LABEL_PAD : 0; + const float pad_bot = (ImHasFlag(plot.XAxis.Flags, ImPlotAxisFlags_TickLabels) ? txt_height + IMPLOT_LABEL_PAD : 0) + (x_label ? txt_height + IMPLOT_LABEL_PAD : 0); + YPadCalculator y_axis_pad(gp.Y, max_label_width, IMPLOT_LABEL_PAD); + const float pad_left = y_axis_pad(0) + (y_label ? txt_height + IMPLOT_LABEL_PAD : 0); const float pad_right = y_axis_pad(1) + y_axis_pad(2); gp.BB_Plot = ImRect(gp.BB_Canvas.Min + ImVec2(pad_left, pad_top), gp.BB_Canvas.Max - ImVec2(pad_right, pad_bot)); gp.Hov_Plot = gp.BB_Plot.Contains(IO.MousePos); @@ -742,7 +756,7 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons gp.BB_Plot.Max.x : (gp.AxisLabelReference[1] + y_axis_pad(1) + 6); - ImRect yAxisRegion_bb[MAX_Y_AXES]; + ImRect yAxisRegion_bb[IMPLOT_Y_AXES]; yAxisRegion_bb[0] = ImRect(ImVec2(gp.BB_Frame.Min.x, gp.BB_Plot.Min.y), ImVec2(gp.BB_Plot.Min.x + 6, gp.BB_Plot.Max.y - 10)); // The auxiliary y axes are off to the right of the BB grid. yAxisRegion_bb[1] = ImRect(ImVec2(gp.BB_Plot.Max.x - 6, gp.BB_Plot.Min.y), gp.BB_Plot.Max + ImVec2(y_axis_pad(1), -10)); @@ -793,9 +807,9 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons plot.XAxis.Dragging = false; G.IO.MouseDragMaxDistanceSqr[0] = 0; } - for (int i = 0; i < MAX_Y_AXES; i++) { + for (int i = 0; i < IMPLOT_Y_AXES; i++) { if (plot.YAxis[i].Dragging && (IO.MouseReleased[gp.InputMap.PanButton] || !IO.MouseDown[gp.InputMap.PanButton])) { - plot.YAxis[i].Dragging = false; + plot.YAxis[i].Dragging = false; G.IO.MouseDragMaxDistanceSqr[0] = 0; } } @@ -812,7 +826,7 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons if (!gp.X.LockMax) plot.XAxis.Range.Max = gp.X.Invert ? plot_tl.x : plot_br.x; } - for (int i = 0; i < MAX_Y_AXES; i++) { + for (int i = 0; i < IMPLOT_Y_AXES; i++) { if (!gp.Y[i].Lock && plot.YAxis[i].Dragging) { ImPlotPoint plot_tl = PixelsToPlot(gp.BB_Plot.Min - IO.MouseDelta, i); ImPlotPoint plot_br = PixelsToPlot(gp.BB_Plot.Max - IO.MouseDelta, i); @@ -828,7 +842,7 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons if (!gp.X.Lock && plot.XAxis.Dragging) { direction |= (1 << 1); } - for (int i = 0; i < MAX_Y_AXES; i++) { + for (int i = 0; i < IMPLOT_Y_AXES; i++) { if (!gp.Y[i].Present) { continue; } if (!gp.Y[i].Lock && plot.YAxis[i].Dragging) { direction |= (1 << 2); @@ -836,18 +850,14 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons } } if (IO.MouseDragMaxDistanceSqr[0] > 5) { - if (direction == 0) { - ImGui::SetMouseCursor(ImGuiMouseCursor_NotAllowed); - } - else if (direction == (1 << 1)) { - ImGui::SetMouseCursor(ImGuiMouseCursor_ResizeEW); - } - else if (direction == (1 << 2)) { - ImGui::SetMouseCursor(ImGuiMouseCursor_ResizeNS); - } - else { - ImGui::SetMouseCursor(ImGuiMouseCursor_ResizeAll); - } + if (direction == 0) + ImGui::SetMouseCursor(ImGuiMouseCursor_NotAllowed); + else if (direction == (1 << 1)) + ImGui::SetMouseCursor(ImGuiMouseCursor_ResizeEW); + else if (direction == (1 << 2)) + ImGui::SetMouseCursor(ImGuiMouseCursor_ResizeNS); + else + ImGui::SetMouseCursor(ImGuiMouseCursor_ResizeAll); } } // start drag @@ -855,7 +865,7 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons if (plot.XAxis.Hovered) { plot.XAxis.Dragging = true; } - for (int i = 0; i < MAX_Y_AXES; i++) { + for (int i = 0; i < IMPLOT_Y_AXES; i++) { if (plot.YAxis[i].Hovered) { plot.YAxis[i].Dragging = true; } @@ -866,7 +876,7 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons if (gp.Hov_Frame && (plot.XAxis.Hovered || any_hov_y_axis_region) && IO.MouseWheel != 0) { UpdateTransformCache(); - float zoom_rate = 0.1f; + float zoom_rate = IMPLOT_ZOOM_RATE; if (IO.MouseWheel > 0) zoom_rate = (-zoom_rate) / (1.0f + (2.0f * zoom_rate)); float tx = ImRemap(IO.MousePos.x, gp.BB_Plot.Min.x, gp.BB_Plot.Max.x, 0.0f, 1.0f); @@ -881,7 +891,7 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons if (!gp.X.LockMax) plot.XAxis.Range.Max = gp.X.Invert ? plot_tl.x : plot_br.x; } - for (int i = 0; i < MAX_Y_AXES; i++) { + for (int i = 0; i < IMPLOT_Y_AXES; i++) { if (plot.YAxis[i].Hovered && !gp.Y[i].Lock) { ImPlotAxisScale axis_scale(i, tx, ty, zoom_rate); const ImPlotPoint& plot_tl = axis_scale.Min; @@ -907,7 +917,7 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons plot.XAxis.Range.Min = ImMin(p1.x, p2.x); if (!gp.X.LockMax && IO.KeyMods != gp.InputMap.HorizontalMod) plot.XAxis.Range.Max = ImMax(p1.x, p2.x); - for (int i = 0; i < MAX_Y_AXES; i++) { + for (int i = 0; i < IMPLOT_Y_AXES; i++) { p1 = PixelsToPlot(plot.SelectStart, i); p2 = PixelsToPlot(IO.MousePos, i); if (!gp.Y[i].LockMin && IO.KeyMods != gp.InputMap.VerticalMod) @@ -945,12 +955,10 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons // end query if (plot.Querying && (IO.MouseReleased[gp.InputMap.QueryButton] || IO.MouseReleased[gp.InputMap.BoxSelectButton])) { plot.Querying = false; - if (plot.QueryRect.GetWidth() > 2 && plot.QueryRect.GetHeight() > 2) { - plot.Queried = true; - } - else { - plot.Queried = false; - } + if (plot.QueryRect.GetWidth() > 2 && plot.QueryRect.GetHeight() > 2) + plot.Queried = true; + else + plot.Queried = false; } // begin query @@ -980,16 +988,14 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons if ( IO.MouseDoubleClicked[gp.InputMap.FitButton] && gp.Hov_Frame && (plot.XAxis.Hovered || any_hov_y_axis_region) && !hov_legend && !hov_query) { gp.FitThisFrame = true; gp.FitX = plot.XAxis.Hovered; - for (int i = 0; i < MAX_Y_AXES; i++) { - gp.FitY[i] = plot.YAxis[i].Hovered; - } + for (int i = 0; i < IMPLOT_Y_AXES; i++) + gp.FitY[i] = plot.YAxis[i].Hovered; } else { gp.FitThisFrame = false; gp.FitX = false; - for (int i = 0; i < MAX_Y_AXES; i++) { - gp.FitY[i] = false; - } + for (int i = 0; i < IMPLOT_Y_AXES; i++) + gp.FitY[i] = false; } // FOCUS ------------------------------------------------------------------ @@ -1001,7 +1007,7 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons UpdateTransformCache(); // set mouse position - for (int i = 0; i < MAX_Y_AXES; i++) { + for (int i = 0; i < IMPLOT_Y_AXES; i++) { gp.LastMousePos[i] = PixelsToPlot(IO.MousePos, i); } @@ -1020,7 +1026,7 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons xt->PixelPos = PlotToPixels(xt->PlotPos, 0, 0).x; } } - for (int i = 0; i < MAX_Y_AXES; i++) { + for (int i = 0; i < IMPLOT_Y_AXES; i++) { if (gp.RenderY[i]) { for (int t = 0; t < gp.YTicks[i].Size; t++) { ImPlotTick *yt = &gp.YTicks[i][t]; @@ -1037,7 +1043,7 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons } } - for (int i = 0; i < MAX_Y_AXES; i++) { + for (int i = 0; i < IMPLOT_Y_AXES; i++) { if (gp.Y[i].Present && ImHasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_GridLines)) { for (int t = 0; t < gp.YTicks[i].Size; t++) { ImPlotTick *yt = &gp.YTicks[i][t]; @@ -1058,8 +1064,8 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons ImGui::PushClipRect(gp.BB_Frame.Min, gp.BB_Frame.Max, true); for (int t = 0; t < gp.XTicks.Size; t++) { ImPlotTick *xt = &gp.XTicks[t]; - if (xt->RenderLabel && xt->PixelPos >= gp.BB_Plot.Min.x - 1 && xt->PixelPos <= gp.BB_Plot.Max.x + 1) - DrawList.AddText(ImVec2(xt->PixelPos - xt->Size.x * 0.5f, gp.BB_Plot.Max.y + txt_off), gp.Col_X.Txt, gp.XTickLabels.Buf.Data + xt->TextOffset); + if (xt->ShowLabel && xt->PixelPos >= gp.BB_Plot.Min.x - 1 && xt->PixelPos <= gp.BB_Plot.Max.x + 1) + DrawList.AddText(ImVec2(xt->PixelPos - xt->LabelSize.x * 0.5f, gp.BB_Plot.Max.y + IMPLOT_LABEL_PAD), xt->Major ? gp.Col_X.MajTxt : gp.Col_X.MinTxt, gp.XTickLabels.Buf.Data + xt->BufferOffset); } ImGui::PopClipRect(); } @@ -1067,17 +1073,17 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons const ImVec2 xLabel_size = ImGui::CalcTextSize(x_label); const ImVec2 xLabel_pos(gp.BB_Plot.GetCenter().x - xLabel_size.x * 0.5f, gp.BB_Canvas.Max.y - txt_height); - DrawList.AddText(xLabel_pos, gp.Col_X.Txt, x_label); + DrawList.AddText(xLabel_pos, gp.Col_X.MajTxt, x_label); } ImGui::PushClipRect(gp.BB_Frame.Min, gp.BB_Frame.Max, true); - for (int i = 0; i < MAX_Y_AXES; i++) { + for (int i = 0; i < IMPLOT_Y_AXES; i++) { if (gp.Y[i].Present && ImHasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_TickLabels)) { for (int t = 0; t < gp.YTicks[i].Size; t++) { - const float x_start = gp.AxisLabelReference[i] + (i == 0 ? (-txt_off - gp.YTicks[i][t].Size.x) : txt_off); + const float x_start = gp.AxisLabelReference[i] + (i == 0 ? (-IMPLOT_LABEL_PAD - gp.YTicks[i][t].LabelSize.x) : IMPLOT_LABEL_PAD); ImPlotTick *yt = &gp.YTicks[i][t]; - if (yt->RenderLabel && yt->PixelPos >= gp.BB_Plot.Min.y - 1 && yt->PixelPos <= gp.BB_Plot.Max.y + 1) { - ImVec2 start(x_start, yt->PixelPos - 0.5f * yt->Size.y); - DrawList.AddText(start, gp.Col_Y[i].Txt, gp.YTickLabels[i].Buf.Data + yt->TextOffset); + if (yt->ShowLabel && yt->PixelPos >= gp.BB_Plot.Min.y - 1 && yt->PixelPos <= gp.BB_Plot.Max.y + 1) { + ImVec2 start(x_start, yt->PixelPos - 0.5f * yt->LabelSize.y); + DrawList.AddText(start, yt->Major ? gp.Col_Y[i].MajTxt : gp.Col_Y[i].MinTxt, gp.YTickLabels[i].Buf.Data + yt->BufferOffset); } } } @@ -1086,7 +1092,7 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons if (y_label) { const ImVec2 yLabel_size = CalcTextSizeVertical(y_label); const ImVec2 yLabel_pos(gp.BB_Canvas.Min.x, gp.BB_Plot.GetCenter().y + yLabel_size.y * 0.5f); - AddTextVertical(&DrawList, y_label, yLabel_pos, gp.Col_Y[0].Txt); + AddTextVertical(&DrawList, y_label, yLabel_pos, gp.Col_Y[0].MajTxt); } // push plot ID into stack @@ -1179,7 +1185,7 @@ void PlotContextMenu(ImPlotState& plot) { ImGui::PopID(); ImGui::EndMenu(); } - for (int i = 0; i < MAX_Y_AXES; i++) { + for (int i = 0; i < IMPLOT_Y_AXES; i++) { if (i == 1 && !ImHasFlag(plot.Flags, ImPlotFlags_YAxis2)) { continue; } @@ -1241,13 +1247,13 @@ void PlotContextMenu(ImPlotState& plot) { void EndPlot() { IM_ASSERT_USER_ERROR(GImPlot != NULL, "No current context. Did you call ImPlot::CreateContext() or ImPlot::SetCurrentContext()?"); - ImPlotContext& gp = *GImPlot; + ImPlotContext& gp = *GImPlot; IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "Mismatched BeginPlot()/EndPlot()!"); - ImGuiContext &G = *GImGui; - ImPlotState &plot = *gp.CurrentPlot; - ImGuiWindow * Window = G.CurrentWindow; + ImGuiContext &G = *GImGui; + ImPlotState &plot = *gp.CurrentPlot; + ImGuiWindow * Window = G.CurrentWindow; ImDrawList & DrawList = *Window->DrawList; - const ImGuiIO & IO = ImGui::GetIO(); + const ImGuiIO & IO = ImGui::GetIO(); // AXIS STATES ------------------------------------------------------------ @@ -1262,14 +1268,14 @@ void EndPlot() { if (ImHasFlag(plot.XAxis.Flags, ImPlotAxisFlags_TickMarks)) { for (int t = 0; t < gp.XTicks.Size; t++) { ImPlotTick *xt = &gp.XTicks[t]; - DrawList.AddLine(ImVec2(xt->PixelPos, gp.BB_Plot.Max.y),ImVec2(xt->PixelPos, gp.BB_Plot.Max.y - (xt->Major ? 10.0f : 5.0f)), gp.Col_Border, 1); + DrawList.AddLine(ImVec2(xt->PixelPos, gp.BB_Plot.Max.y),ImVec2(xt->PixelPos, gp.BB_Plot.Max.y - (xt->Major ? IMPLOT_MAJOR_SIZE : IMPLOT_MINOR_SIZE)), gp.Col_Border, 1); } } PopPlotClipRect(); ImGui::PushClipRect(gp.BB_Plot.Min, ImVec2(gp.BB_Frame.Max.x, gp.BB_Plot.Max.y), true); int axis_count = 0; - for (int i = 0; i < MAX_Y_AXES; i++) { + for (int i = 0; i < IMPLOT_Y_AXES; i++) { if (!gp.Y[i].Present) { continue; } axis_count++; @@ -1277,14 +1283,13 @@ void EndPlot() { if (ImHasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_TickMarks)) { float direction = (i == 0) ? 1.0f : -1.0f; bool no_major = axis_count >= 3; - for (int t = 0; t < gp.YTicks[i].Size; t++) { ImPlotTick *yt = &gp.YTicks[i][t]; ImVec2 start = ImVec2(x_start, yt->PixelPos); DrawList.AddLine( start, - start + ImVec2(direction * ((!no_major && yt->Major) ? 10.0f : 5.0f), 0), + start + ImVec2(direction * ((!no_major && yt->Major) ? IMPLOT_MAJOR_SIZE : IMPLOT_MINOR_SIZE), 0), gp.Col_Border, 1); } } @@ -1304,7 +1309,7 @@ void EndPlot() { ImRect bb_plot_pad = gp.BB_Plot; bb_plot_pad.Min.x += 5; bb_plot_pad.Max.x -= 5; if (!bb_plot_pad.Contains(IO.MousePos)) { - for (int i = 0; i < MAX_Y_AXES; ++i) { + for (int i = 0; i < IMPLOT_Y_AXES; ++i) { if (plot.YAxis[i].Hovered) { float x_loc = gp.AxisLabelReference[i]; ImVec2 p1(x_loc - 5, gp.BB_Plot.Min.y - 5); @@ -1315,7 +1320,6 @@ void EndPlot() { } } - PushPlotClipRect(); // render selection/query if (plot.Selecting) { @@ -1472,7 +1476,7 @@ void EndPlot() { if (gp.FitX && !ImHasFlag(plot.XAxis.Flags, ImPlotAxisFlags_LockMax) && !NanOrInf(gp.ExtentsX.Max)) { plot.XAxis.Range.Max = gp.ExtentsX.Max; } - for (int i = 0; i < MAX_Y_AXES; i++) { + for (int i = 0; i < IMPLOT_Y_AXES; i++) { if (gp.FitY[i] && !ImHasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_LockMin) && !NanOrInf(gp.ExtentsY[i].Min)) { plot.YAxis[i].Range.Min = gp.ExtentsY[i].Min; } @@ -1530,7 +1534,7 @@ void SetNextPlotLimitsX(double x_min, double x_max, ImGuiCond cond) { void SetNextPlotLimitsY(double y_min, double y_max, ImGuiCond cond, int y_axis) { ImPlotContext& gp = *GImPlot; IM_ASSERT_USER_ERROR(gp.CurrentPlot == NULL, "SetNextPlotLimitsY() needs to be called before BeginPlot()!"); - IM_ASSERT_USER_ERROR(y_axis >= 0 && y_axis < MAX_Y_AXES, "y_axis needs to be between 0 and MAX_Y_AXES"); + IM_ASSERT_USER_ERROR(y_axis >= 0 && y_axis < IMPLOT_Y_AXES, "y_axis needs to be between 0 and IMPLOT_Y_AXES"); IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags. gp.NextPlotData.HasYRange[y_axis] = true; gp.NextPlotData.YRangeCond[y_axis] = cond; @@ -1555,7 +1559,7 @@ void SetNextPlotTicksX(double x_min, double x_max, int n_ticks, const char** lab void SetNextPlotTicksY(const double* values, int n_ticks, const char** labels, bool show_default, int y_axis) { ImPlotContext& gp = *GImPlot; IM_ASSERT_USER_ERROR(gp.CurrentPlot == NULL, "SetNextPlotTicksY() needs to be called before BeginPlot()!"); - IM_ASSERT_USER_ERROR(y_axis >= 0 && y_axis < MAX_Y_AXES, "y_axis needs to be between 0 and MAX_Y_AXES"); + IM_ASSERT_USER_ERROR(y_axis >= 0 && y_axis < IMPLOT_Y_AXES, "y_axis needs to be between 0 and IMPLOT_Y_AXES"); gp.NextPlotData.ShowDefaultTicksY[y_axis] = show_default; AddCustomTicks(values, labels, n_ticks, gp.YTicks[y_axis], gp.YTickLabels[y_axis]); } @@ -1570,7 +1574,7 @@ void SetNextPlotTicksY(double y_min, double y_max, int n_ticks, const char** lab void SetPlotYAxis(int y_axis) { ImPlotContext& gp = *GImPlot; IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "SetPlotYAxis() needs to be called between BeginPlot() and EndPlot()!"); - IM_ASSERT_USER_ERROR(y_axis >= 0 && y_axis < MAX_Y_AXES, "y_axis needs to be between 0 and MAX_Y_AXES"); + IM_ASSERT_USER_ERROR(y_axis >= 0 && y_axis < IMPLOT_Y_AXES, "y_axis needs to be between 0 and IMPLOT_Y_AXES"); gp.CurrentPlot->CurrentYAxis = y_axis; } @@ -1611,7 +1615,7 @@ bool IsPlotXAxisHovered() { bool IsPlotYAxisHovered(int y_axis_in) { ImPlotContext& gp = *GImPlot; - IM_ASSERT_USER_ERROR(y_axis_in >= -1 && y_axis_in < MAX_Y_AXES, "y_axis needs to between -1 and MAX_Y_AXES"); + IM_ASSERT_USER_ERROR(y_axis_in >= -1 && y_axis_in < IMPLOT_Y_AXES, "y_axis needs to between -1 and IMPLOT_Y_AXES"); IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "IsPlotYAxisHovered() needs to be called between BeginPlot() and EndPlot()!"); const int y_axis = y_axis_in >= 0 ? y_axis_in : gp.CurrentPlot->CurrentYAxis; ImRect bb_plot_pad = gp.BB_Plot; @@ -1621,7 +1625,7 @@ bool IsPlotYAxisHovered(int y_axis_in) { ImPlotPoint GetPlotMousePos(int y_axis_in) { ImPlotContext& gp = *GImPlot; - IM_ASSERT_USER_ERROR(y_axis_in >= -1 && y_axis_in < MAX_Y_AXES, "y_axis needs to between -1 and MAX_Y_AXES"); + IM_ASSERT_USER_ERROR(y_axis_in >= -1 && y_axis_in < IMPLOT_Y_AXES, "y_axis needs to between -1 and IMPLOT_Y_AXES"); IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "GetPlotMousePos() needs to be called between BeginPlot() and EndPlot()!"); const int y_axis = y_axis_in >= 0 ? y_axis_in : gp.CurrentPlot->CurrentYAxis; return gp.LastMousePos[y_axis]; @@ -1630,7 +1634,7 @@ ImPlotPoint GetPlotMousePos(int y_axis_in) { ImPlotLimits GetPlotLimits(int y_axis_in) { ImPlotContext& gp = *GImPlot; - IM_ASSERT_USER_ERROR(y_axis_in >= -1 && y_axis_in < MAX_Y_AXES, "y_axis needs to between -1 and MAX_Y_AXES"); + IM_ASSERT_USER_ERROR(y_axis_in >= -1 && y_axis_in < IMPLOT_Y_AXES, "y_axis needs to between -1 and IMPLOT_Y_AXES"); IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "GetPlotLimits() needs to be called between BeginPlot() and EndPlot()!"); const int y_axis = y_axis_in >= 0 ? y_axis_in : gp.CurrentPlot->CurrentYAxis; @@ -1649,7 +1653,7 @@ bool IsPlotQueried() { ImPlotLimits GetPlotQuery(int y_axis_in) { ImPlotContext& gp = *GImPlot; - IM_ASSERT_USER_ERROR(y_axis_in >= -1 && y_axis_in < MAX_Y_AXES, "y_axis needs to between -1 and MAX_Y_AXES"); + IM_ASSERT_USER_ERROR(y_axis_in >= -1 && y_axis_in < IMPLOT_Y_AXES, "y_axis needs to between -1 and IMPLOT_Y_AXES"); IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "GetPlotQuery() needs to be called between BeginPlot() and EndPlot()!"); ImPlotState& plot = *gp.CurrentPlot; const int y_axis = y_axis_in >= 0 ? y_axis_in : gp.CurrentPlot->CurrentYAxis; @@ -1843,7 +1847,7 @@ void ShowColormapScale(double scale_min, double scale_max, float height) { LabelTicks(ticks, false, txt_buff); float max_width = 0; for (int i = 0; i < ticks.Size; ++i) - max_width = ticks[i].Size.x > max_width ? ticks[i].Size.x : max_width; + max_width = ticks[i].LabelSize.x > max_width ? ticks[i].LabelSize.x : max_width; ImGuiContext &G = *GImGui; ImGuiWindow * Window = G.CurrentWindow; @@ -1877,7 +1881,7 @@ void ShowColormapScale(double scale_min, double scale_max, float height) { float ypos = ImRemap((float)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[i].Major ? 10.0f : 5.0f), ypos), col_border, 1.0f); - DrawList.AddText(ImVec2(bb_grad.Max.x-1, ypos) + ImVec2(txt_off, -ticks[i].Size.y * 0.5f), ImGui::GetColorU32(ImGuiCol_Text), txt_buff.Buf.Data + ticks[i].TextOffset); + DrawList.AddText(ImVec2(bb_grad.Max.x-1, ypos) + ImVec2(txt_off, -ticks[i].LabelSize.y * 0.5f), ImGui::GetColorU32(ImGuiCol_Text), txt_buff.Buf.Data + ticks[i].BufferOffset); } ImGui::PopClipRect(); diff --git a/implot.h b/implot.h index a9a8b04..971f79e 100644 --- a/implot.h +++ b/implot.h @@ -151,8 +151,9 @@ struct ImPlotPoint { struct ImPlotRange { double Min, Max; ImPlotRange(); - bool Contains(double value) const { return value >= Min && value <= Max; }; - double Size() const { return Max - Min; }; + ImPlotRange(double _min, double _max) { Min = _min; Max = _max; } + bool Contains(double value) const { return value >= Min && value <= Max; }; + double Size() const { return Max - Min; }; }; // Combination of two ranges for X and Y axes. diff --git a/implot_demo.cpp b/implot_demo.cpp index 8208f89..f0bedd9 100644 --- a/implot_demo.cpp +++ b/implot_demo.cpp @@ -762,7 +762,7 @@ void ShowDemoWindow(bool* p_open) { } } ImPlot::SetNextPlotLimitsX((double)t - 10, t, paused ? ImGuiCond_Once : ImGuiCond_Always); - if (ImPlot::BeginPlot("##DND", NULL, NULL, ImVec2(-1,0), ImPlotFlags_Legend | ImPlotFlags_Highlight | ImPlotFlags_BoxSelect | ImPlotFlags_ContextMenu | ImPlotFlags_NoChild | ImPlotFlags_YAxis2 | ImPlotFlags_YAxis3)) { + if (ImPlot::BeginPlot("##DND", NULL, NULL, ImVec2(-1,0), ImPlotFlags_Legend | ImPlotFlags_Highlight | ImPlotFlags_BoxSelect | ImPlotFlags_ContextMenu | ImPlotFlags_YAxis2 | ImPlotFlags_YAxis3)) { for (int i = 0; i < K_CHANNELS; ++i) { if (show[i] && data[i].Data.size() > 0) { char label[K_CHANNELS]; diff --git a/implot_internal.h b/implot_internal.h index 0749238..c9d5cec 100644 --- a/implot_internal.h +++ b/implot_internal.h @@ -26,7 +26,7 @@ // don't provide any guarantee of forward compatibility! //----------------------------------------------------------------------------- -// [SECTION] Header mess +// [SECTION] Header Mess //----------------------------------------------------------------------------- #pragma once @@ -42,7 +42,7 @@ #endif //----------------------------------------------------------------------------- -// [SECTION] Forward declarations +// [SECTION] Forward Declarations //----------------------------------------------------------------------------- struct ImPlotTick; @@ -54,20 +54,40 @@ struct ImPlotState; struct ImPlotNextPlotData; //----------------------------------------------------------------------------- -// [SECTION] Context pointer +// [SECTION] Context Pointer //----------------------------------------------------------------------------- extern ImPlotContext* GImPlot; // Current implicit context pointer //----------------------------------------------------------------------------- -// [SECTION] Macros +// [SECTION] Macros and Constants //----------------------------------------------------------------------------- +// Constants can be changed unless stated otherwise + +// Default plot frame width when requested width is auto (i.e. 0). This is not the plot area width! +#define IMPLOT_DEFAULT_W 400 +// Default plot frame height when requested height is auto (i.e. 0). This is not the plot area height! +#define IMPLOT_DEFAULT_H 300 +// Minimum plot frame width when requested width is to edge (i.e. -1). This is not the plot area width! +#define IMPLOT_MIN_W 300 +// Minimum plot frame height when requested height is to edge (i.e. -1). This is not the plot area height! +#define IMPLOT_MIN_H 225 // The maximum number of supported y-axes (DO NOT CHANGE THIS) -#define MAX_Y_AXES 3 +#define IMPLOT_Y_AXES 3 +// The number of times to subdivided grid divisions (best if a multiple of 1, 2, and 5) +#define IMPLOT_SUB_DIV 10 +// Pixel padding used for labels/titles +#define IMPLOT_LABEL_PAD 5 +// Major tick size in pixels +#define IMPLOT_MAJOR_SIZE 10 +// Minor tick size in pixels +#define IMPLOT_MINOR_SIZE 5 +// Zoom rate for scroll (e.g. 0.1f = 10% plot range every scroll click) +#define IMPLOT_ZOOM_RATE 0.1f //----------------------------------------------------------------------------- -// [SECTION] Generic helpers +// [SECTION] Generic Helpers //----------------------------------------------------------------------------- // Computes the common (base-10) logarithm @@ -151,17 +171,17 @@ struct ImPlotTick { double PlotPos; float PixelPos; - ImVec2 Size; - int TextOffset; + ImVec2 LabelSize; + int BufferOffset; bool Major; - bool RenderLabel; + bool ShowLabel; bool Labeled; - ImPlotTick(double value, bool major, bool render_label = true) { - PlotPos = value; - Major = major; - RenderLabel = render_label; - Labeled = false; + ImPlotTick(double value, bool major, bool show_label) { + PlotPos = value; + Major = major; + ShowLabel = show_label; + Labeled = false; } }; @@ -213,8 +233,8 @@ struct ImPlotAxisState struct ImPlotAxisColor { - ImU32 Major, Minor, Txt; - ImPlotAxisColor() { Major = Minor = Txt = 0; } + ImU32 Major, Minor, MajTxt, MinTxt; + ImPlotAxisColor() { Major = Minor = MajTxt = MinTxt = 0; } }; // State information for Plot items @@ -245,7 +265,7 @@ struct ImPlotState ImPlotFlags Flags; ImPlotFlags PreviousFlags; ImPlotAxis XAxis; - ImPlotAxis YAxis[MAX_Y_AXES]; + ImPlotAxis YAxis[IMPLOT_Y_AXES]; ImPool Items; ImVec2 SelectStart; ImVec2 QueryStart; @@ -270,18 +290,18 @@ struct ImPlotState struct ImPlotNextPlotData { ImGuiCond XRangeCond; - ImGuiCond YRangeCond[MAX_Y_AXES]; + ImGuiCond YRangeCond[IMPLOT_Y_AXES]; ImPlotRange X; - ImPlotRange Y[MAX_Y_AXES]; + ImPlotRange Y[IMPLOT_Y_AXES]; bool HasXRange; - bool HasYRange[MAX_Y_AXES]; + bool HasYRange[IMPLOT_Y_AXES]; bool ShowDefaultTicksX; - bool ShowDefaultTicksY[MAX_Y_AXES]; + bool ShowDefaultTicksY[IMPLOT_Y_AXES]; ImPlotNextPlotData() { HasXRange = false; ShowDefaultTicksX = true; - for (int i = 0; i < MAX_Y_AXES; ++i) { + for (int i = 0; i < IMPLOT_Y_AXES; ++i) { HasYRange[i] = false; ShowDefaultTicksY[i] = true; } @@ -316,30 +336,30 @@ struct ImPlotContext { // Axis States ImPlotAxisColor Col_X; - ImPlotAxisColor Col_Y[MAX_Y_AXES]; + ImPlotAxisColor Col_Y[IMPLOT_Y_AXES]; ImPlotAxisState X; - ImPlotAxisState Y[MAX_Y_AXES]; + ImPlotAxisState Y[IMPLOT_Y_AXES]; // Tick Marks and Labels ImVector XTicks; - ImVector YTicks[MAX_Y_AXES]; + ImVector YTicks[IMPLOT_Y_AXES]; ImGuiTextBuffer XTickLabels; - ImGuiTextBuffer YTickLabels[MAX_Y_AXES]; - float AxisLabelReference[MAX_Y_AXES]; + ImGuiTextBuffer YTickLabels[IMPLOT_Y_AXES]; + float AxisLabelReference[IMPLOT_Y_AXES]; // Transformations and Data Extents - ImRect PixelRange[MAX_Y_AXES]; + ImRect PixelRange[IMPLOT_Y_AXES]; double Mx; - double My[MAX_Y_AXES]; + double My[IMPLOT_Y_AXES]; double LogDenX; - double LogDenY[MAX_Y_AXES]; + double LogDenY[IMPLOT_Y_AXES]; ImPlotRange ExtentsX; - ImPlotRange ExtentsY[MAX_Y_AXES]; + ImPlotRange ExtentsY[IMPLOT_Y_AXES]; // Data Fitting Flags bool FitThisFrame; bool FitX; - bool FitY[MAX_Y_AXES]; + bool FitY[IMPLOT_Y_AXES]; // Hover states bool Hov_Frame; @@ -347,7 +367,7 @@ struct ImPlotContext { // Axis Rendering Flags bool RenderX; - bool RenderY[MAX_Y_AXES]; + bool RenderY[IMPLOT_Y_AXES]; // Axis Locking Flags bool LockPlot; @@ -366,7 +386,7 @@ struct ImPlotContext { int DigitalPlotOffset; ImPlotNextPlotData NextPlotData; ImPlotInputMap InputMap; - ImPlotPoint LastMousePos[MAX_Y_AXES]; + ImPlotPoint LastMousePos[IMPLOT_Y_AXES]; }; struct ImPlotAxisScale @@ -422,8 +442,13 @@ void AddDefaultTicks(const ImPlotRange& range, int nMajor, int nMinor, bool logs void AddCustomTicks(const double* values, const char** labels, int n, ImVector& ticks, ImGuiTextBuffer& buffer); // Creates label information for a list of ImPlotTick void LabelTicks(ImVector &ticks, bool scientific, ImGuiTextBuffer& buffer); -// Calculates the maximum width of a list of ImPlotTick -float MaxTickLabelWidth(ImVector& ticks); +// Gets the widest visible (i.e. ShowLabel = true) label size from a list of ticks +float MaxTickLabelWidth(const ImVector& ticks); +// Sums the widths of visible ticks (i.e. ShowLabel = true) ticks +float SumTickLabelWidth(const ImVector& ticks); +// Sums the heights of visible (i.e. ShowLabel = true) ticks +float SumTickLabelHeight(const ImVector& ticks); + // Rounds x to powers of 2,5 and 10 for generating axis labels (from Graphics Gems 1 Chapter 11.2) double NiceNum(double x, bool round);