diff --git a/implot.cpp b/implot.cpp index 725fe6f..c7bb446 100644 --- a/implot.cpp +++ b/implot.cpp @@ -20,7 +20,26 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -// ImPlot v0.1 WIP +// ImPlot v0.2 WIP + +/* + +API BREAKING CHANGES +==================== +Occasionally introducing changes that are breaking the API. We try to make the breakage minor and easy to fix. +Below is a change-log of API breaking changes only. If you are using one of the functions listed, expect to have to fix some code. +When you are not sure about a old symbol or function name, try using the Search/Find function of your IDE to look for comments or references in all implot files. +You can read releases logs https://github.com/epezent/implot/releases for more details. + +- 2020/05/10 (0.2) - The following function/struct names were changes: + - ImPlotRange -> ImPlotLimits + - GetPlotRange() -> GetPlotLimits() + - SetNextPlotRange -> SetNextPlotLimits + - SetNextPlotRangeX -> SetNextPlotLimitsX + - SetNextPlotRangeY -> SetNextPlotLimitsY +- 2020/05/10 (0.2) - Plot queries are pixel based by default. Query rects that maintain relative plot position have been removed. This was done to support multi-y-axis. + +*/ #ifdef _MSC_VER #pragma warning (disable: 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen @@ -30,6 +49,7 @@ #define IMGUI_DEFINE_MATH_OPERATORS #endif + #include #include @@ -45,6 +65,8 @@ // Special Color used to specific that a plot item color should set determined automatically. #define IM_COL_AUTO ImVec4(0,0,0,-1) +// The maximum number of support y-axes +#define MAX_Y_AXES 3 ImPlotStyle::ImPlotStyle() { LineWeight = 1; @@ -65,8 +87,8 @@ ImPlotStyle::ImPlotStyle() { Colors[ImPlotCol_PlotBorder] = IM_COL_AUTO; Colors[ImPlotCol_XAxis] = IM_COL_AUTO; Colors[ImPlotCol_YAxis] = IM_COL_AUTO; - Colors[ImPlotCol_Y2Axis] = IM_COL_AUTO; - Colors[ImPlotCol_Y3Axis] = IM_COL_AUTO; + Colors[ImPlotCol_YAxis2] = IM_COL_AUTO; + Colors[ImPlotCol_YAxis3] = IM_COL_AUTO; Colors[ImPlotCol_Selection] = ImVec4(1,1,0,1); Colors[ImPlotCol_Query] = ImVec4(0,1,0,1); } @@ -81,9 +103,9 @@ float ImPlotRange::Size() const { return Max - Min; } -ImPlotBounds::ImPlotBounds() {} +ImPlotLimits::ImPlotLimits() {} -bool ImPlotBounds::Contains(const ImVec2& p) const { +bool ImPlotLimits::Contains(const ImVec2& p) const { return X.Contains(p.x) && Y.Contains(p.y); } @@ -91,8 +113,6 @@ namespace ImGui { namespace { -#define MAX_Y_AXES 3 - //----------------------------------------------------------------------------- // Private Utils //----------------------------------------------------------------------------- @@ -242,13 +262,13 @@ struct ImPlotAxis { Range.Max = 1; Divisions = 3; Subdivisions = 10; - Flags = ImAxisFlags_Default; + Flags = PreviousFlags = ImAxisFlags_Default; } bool Dragging; ImPlotRange Range; int Divisions; int Subdivisions; - ImAxisFlags Flags; + ImAxisFlags Flags, PreviousFlags; }; /// Holds Plot state information that must persist between frames @@ -256,7 +276,7 @@ struct ImPlot { ImPlot() { Selecting = Querying = Queried = DraggingQuery = false; SelectStart = QueryStart = ImVec2(0,0); - Flags = ImPlotFlags_Default; + Flags = PreviousFlags = ImPlotFlags_Default; ColorIdx = 0; CurrentYAxis = 0; } @@ -274,17 +294,17 @@ struct ImPlot { ImPlotAxis XAxis; ImPlotAxis YAxis[MAX_Y_AXES]; - ImPlotFlags Flags; + ImPlotFlags Flags, PreviousFlags; int ColorIdx; int CurrentYAxis; }; struct ImNextPlotData { - ImNextPlotData() : HasXBounds{}, HasYBounds{} {} - ImGuiCond XBoundsCond; - ImGuiCond YBoundsCond[MAX_Y_AXES]; - bool HasXBounds; - bool HasYBounds[MAX_Y_AXES]; + ImNextPlotData() : HasXRange{}, HasYRange{} {} + ImGuiCond XRangeCond; + ImGuiCond YRangeCond[MAX_Y_AXES]; + bool HasXRange; + bool HasYRange[MAX_Y_AXES]; ImPlotRange X; ImPlotRange Y[MAX_Y_AXES]; }; @@ -642,7 +662,7 @@ ImRect GetAxisScale(int y_axis, float tx, float ty, float zoom_rate) { class YPadCalculator { public: - YPadCalculator(const AxisState* axis_states, const float* max_label_widths, int txt_off) + YPadCalculator(const AxisState* axis_states, const float* max_label_widths, float txt_off) : AxisStates(axis_states), MaxLabelWidths(max_label_widths), TxtOff(txt_off) {} float operator()(int y_axis) { @@ -650,9 +670,9 @@ class YPadCalculator { if (!AxisStates[y_axis].present) { return 0; } // If we have more than 1 axis present before us, then we need // extra space to account for our tick bar. - int pad_result = 0; + float pad_result = 0; if (AxisStates[y_axis].present_so_far >= 3) { - pad_result += 6; + pad_result += 6.0f; } if (!HasFlag(plot.YAxis[y_axis].Flags, ImAxisFlags_TickLabels)) { return pad_result; @@ -664,7 +684,7 @@ class YPadCalculator { private: const AxisState* const AxisStates; const float* const MaxLabelWidths; - const int TxtOff; + const float TxtOff; }; } // namespace @@ -695,13 +715,31 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons plot.CurrentYAxis = 0; - plot.Flags = flags; if (just_created) { - plot.XAxis.Flags = x_flags; + plot.Flags = flags; + plot.XAxis.Flags = x_flags; plot.YAxis[0].Flags = y_flags; plot.YAxis[1].Flags = y2_flags; plot.YAxis[2].Flags = y3_flags; } + else { + // TODO: Check which individual flags changed, and only reset those! + // There's probably an easy bit mask trick I'm not aware of. + if (flags != plot.PreviousFlags) + plot.Flags = flags; + if (y_flags != plot.YAxis[0].PreviousFlags) + plot.YAxis[0].PreviousFlags = y_flags; + if (y2_flags != plot.YAxis[1].PreviousFlags) + plot.YAxis[1].PreviousFlags = y2_flags; + if (y3_flags != plot.YAxis[2].PreviousFlags) + plot.YAxis[2].PreviousFlags = y3_flags; + } + + plot.PreviousFlags = flags; + plot.XAxis.PreviousFlags = x_flags; + plot.YAxis[0].PreviousFlags = y_flags; + plot.YAxis[1].PreviousFlags = y2_flags; + plot.YAxis[2].PreviousFlags = y3_flags; // capture scroll with a child region if (!HasFlag(plot.Flags, ImPlotFlags_NoChild)) { @@ -714,16 +752,16 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons // NextPlotData ----------------------------------------------------------- - if (gp.NextPlotData.HasXBounds) { - if (just_created || gp.NextPlotData.XBoundsCond == ImGuiCond_Always) + if (gp.NextPlotData.HasXRange) { + if (just_created || gp.NextPlotData.XRangeCond == ImGuiCond_Always) { plot.XAxis.Range = gp.NextPlotData.X; } } for (int i = 0; i < MAX_Y_AXES; i++) { - if (gp.NextPlotData.HasYBounds[i]) { - if (just_created || gp.NextPlotData.YBoundsCond[i] == ImGuiCond_Always) + if (gp.NextPlotData.HasYRange[i]) { + if (just_created || gp.NextPlotData.YRangeCond[i] == ImGuiCond_Always) { plot.YAxis[i].Range = gp.NextPlotData.Y[i]; } @@ -731,13 +769,13 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons } // AXIS STATES ------------------------------------------------------------ - AxisState x(plot.XAxis, gp.NextPlotData.HasXBounds, gp.NextPlotData.XBoundsCond, true, 0); + AxisState x(plot.XAxis, gp.NextPlotData.HasXRange, gp.NextPlotData.XRangeCond, true, 0); AxisState y[MAX_Y_AXES]; - y[0] = AxisState(plot.YAxis[0], gp.NextPlotData.HasYBounds[0], gp.NextPlotData.YBoundsCond[0], true, 0); - y[1] = AxisState(plot.YAxis[1], gp.NextPlotData.HasYBounds[1], gp.NextPlotData.YBoundsCond[1], - HasFlag(plot.Flags, ImPlotFlags_Y2Axis), y[0].present_so_far); - y[2] = AxisState(plot.YAxis[2], gp.NextPlotData.HasYBounds[2], gp.NextPlotData.YBoundsCond[2], - HasFlag(plot.Flags, ImPlotFlags_Y3Axis), y[1].present_so_far); + y[0] = AxisState(plot.YAxis[0], gp.NextPlotData.HasYRange[0], gp.NextPlotData.YRangeCond[0], true, 0); + y[1] = AxisState(plot.YAxis[1], gp.NextPlotData.HasYRange[1], gp.NextPlotData.YRangeCond[1], + HasFlag(plot.Flags, ImPlotFlags_YAxis2), y[0].present_so_far); + y[2] = AxisState(plot.YAxis[2], gp.NextPlotData.HasYRange[2], gp.NextPlotData.YRangeCond[2], + HasFlag(plot.Flags, ImPlotFlags_YAxis3), y[1].present_so_far); const bool lock_plot = x.lock && y[0].lock && y[1].lock && y[2].lock; @@ -790,8 +828,8 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons UpdateAxisColor(ImPlotCol_XAxis, &gp.Col_X); UpdateAxisColor(ImPlotCol_YAxis, &gp.Col_Y[0]); - UpdateAxisColor(ImPlotCol_Y2Axis, &gp.Col_Y[1]); - UpdateAxisColor(ImPlotCol_Y3Axis, &gp.Col_Y[2]); + UpdateAxisColor(ImPlotCol_YAxis2, &gp.Col_Y[1]); + UpdateAxisColor(ImPlotCol_YAxis3, &gp.Col_Y[2]); gp.Col_Txt = GetColorU32(ImGuiCol_Text); gp.Col_TxtDis = GetColorU32(ImGuiCol_TextDisabled); @@ -866,7 +904,7 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons gp.Hov_Grid = gp.BB_Grid.Contains(IO.MousePos); // axis region bbs - const ImRect xAxisRegion_bb(gp.BB_Grid.Min + ImVec2(10, 0), {gp.BB_Grid.Max.x, gp.BB_Frame.Max.y}); + const ImRect xAxisRegion_bb(gp.BB_Grid.Min + ImVec2(10, 0), ImVec2(gp.BB_Grid.Max.x, gp.BB_Frame.Max.y) - ImVec2(10, 0)); const bool hov_x_axis_region = xAxisRegion_bb.Contains(IO.MousePos); // The left labels are referenced to the left of the bounding box. @@ -897,14 +935,13 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons y[1].present && (yAxisRegion_bb[1].Contains(IO.MousePos) || centralRegion.Contains(IO.MousePos)), y[2].present && (yAxisRegion_bb[2].Contains(IO.MousePos) || centralRegion.Contains(IO.MousePos)), }; - const bool any_hov_y_axis_region = - hov_y_axis_region[0] || hov_y_axis_region[1] || hov_y_axis_region[2]; + const bool any_hov_y_axis_region = hov_y_axis_region[0] || hov_y_axis_region[1] || hov_y_axis_region[2]; // legend hovered from last frame const bool hov_legend = HasFlag(plot.Flags, ImPlotFlags_Legend) ? gp.Hov_Frame && plot.BB_Legend.Contains(IO.MousePos) : false; bool hov_query = false; - if (plot.Queried && !plot.Querying) { + if (gp.Hov_Frame && gp.Hov_Grid && plot.Queried && !plot.Querying) { ImRect bb_query = plot.QueryRect; bb_query.Min += gp.BB_Grid.Min; @@ -922,10 +959,9 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons plot.QueryRect.Min += IO.MouseDelta; plot.QueryRect.Max += IO.MouseDelta; } - if (gp.Hov_Frame && hov_query && !plot.DraggingQuery && !plot.Selecting && !hov_legend) { + if (gp.Hov_Frame && gp.Hov_Grid && hov_query && !plot.DraggingQuery && !plot.Selecting && !hov_legend) { SetMouseCursor(ImGuiMouseCursor_ResizeAll); - const bool any_y_dragging = - plot.YAxis[0].Dragging || plot.YAxis[1].Dragging || plot.YAxis[2].Dragging; + const bool any_y_dragging = plot.YAxis[0].Dragging || plot.YAxis[1].Dragging || plot.YAxis[2].Dragging; if (IO.MouseDown[0] && !plot.XAxis.Dragging && !any_y_dragging) { plot.DraggingQuery = true; } @@ -933,6 +969,7 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons // DRAG INPUT ------------------------------------------------------------- + // end drags if (plot.XAxis.Dragging && (IO.MouseReleased[0] || !IO.MouseDown[0])) { plot.XAxis.Dragging = false; @@ -944,11 +981,10 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons G.IO.MouseDragMaxDistanceSqr[0] = 0; } } + const bool any_y_dragging = plot.YAxis[0].Dragging || plot.YAxis[1].Dragging || plot.YAxis[2].Dragging; + bool drag_in_progress = plot.XAxis.Dragging || any_y_dragging; // do drag - const bool any_y_dragging = - plot.YAxis[0].Dragging || plot.YAxis[1].Dragging || plot.YAxis[2].Dragging; - - if (plot.XAxis.Dragging || any_y_dragging) { + if (drag_in_progress) { UpdateTransformCache(); if (!x.lock && plot.XAxis.Dragging) { ImVec2 plot_tl = PixelsToPlot(gp.BB_Grid.Min - IO.MouseDelta, 0); @@ -993,7 +1029,7 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons } } // start drag - if (gp.Hov_Frame && IO.MouseDragMaxDistanceSqr[0] > 5 && !plot.Selecting && !hov_legend && !hov_query && !plot.DraggingQuery) { + if (!drag_in_progress && gp.Hov_Frame && IO.MouseDragMaxDistanceSqr[0] > 5 && !plot.Selecting && !hov_legend && !hov_query && !plot.DraggingQuery) { if (hov_x_axis_region) { plot.XAxis.Dragging = true; } @@ -1051,6 +1087,8 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons if (!x.lock_max && !IO.KeyAlt) plot.XAxis.Range.Max = ImMax(p1.x, p2.x); for (int i = 0; i < MAX_Y_AXES; i++) { + p1 = PixelsToPlot(plot.SelectStart, i); + p2 = PixelsToPlot(IO.MousePos, i); if (!y[i].lock_min && !IO.KeyShift) plot.YAxis[i].Range.Min = ImMin(p1.y, p2.y); if (!y[i].lock_max && !IO.KeyShift) @@ -1094,21 +1132,21 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons } } // begin query - if ((gp.Hov_Frame && gp.Hov_Grid && IO.MouseClicked[2])) { + if (HasFlag(plot.Flags, ImPlotFlags_Query) && (gp.Hov_Frame && gp.Hov_Grid && IO.MouseClicked[2])) { plot.QueryRect = ImRect(0,0,0,0); plot.Querying = true; plot.Queried = true; plot.QueryStart = IO.MousePos; } // toggle between select/query - if (plot.Selecting && IO.KeyCtrl) { + if (HasFlag(plot.Flags, ImPlotFlags_Query) && plot.Selecting && IO.KeyCtrl) { plot.Selecting = false; plot.QueryRect = ImRect(0,0,0,0); plot.Querying = true; plot.Queried = true; plot.QueryStart = plot.SelectStart; } - if (plot.Querying && !IO.KeyCtrl && !IO.MouseDown[2]) { + if (HasFlag(plot.Flags, ImPlotFlags_Selection) && plot.Querying && !IO.KeyCtrl && !IO.MouseDown[2]) { plot.Selecting = true; plot.Querying = false; plot.Queried = false; @@ -1203,7 +1241,7 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons PushClipRect(gp.BB_Frame.Min, gp.BB_Frame.Max, true); for (int i = 0; i < MAX_Y_AXES; i++) { if (y[i].present && HasFlag(plot.YAxis[i].Flags, ImAxisFlags_TickLabels)) { - const int x_start = + const float x_start = gp.AxisLabelReference[i] + ((i == 0) ? (-txt_off - max_label_width[0]) : @@ -1301,10 +1339,10 @@ void PlotContextMenu(ImPlot& plot) { ImGui::EndMenu(); } for (int i = 0; i < MAX_Y_AXES; i++) { - if (i == 1 && !HasFlag(plot.Flags, ImPlotFlags_Y2Axis)) { + if (i == 1 && !HasFlag(plot.Flags, ImPlotFlags_YAxis2)) { continue; } - if (i == 2 && !HasFlag(plot.Flags, ImPlotFlags_Y3Axis)) { + if (i == 2 && !HasFlag(plot.Flags, ImPlotFlags_YAxis3)) { continue; } char buf[10] = {}; @@ -1396,13 +1434,13 @@ void EndPlot() { // AXIS STATES ------------------------------------------------------------ - AxisState x(plot.XAxis, gp.NextPlotData.HasXBounds, gp.NextPlotData.XBoundsCond, true, 0); + AxisState x(plot.XAxis, gp.NextPlotData.HasXRange, gp.NextPlotData.XRangeCond, true, 0); AxisState y[MAX_Y_AXES]; - y[0] = AxisState(plot.YAxis[0], gp.NextPlotData.HasYBounds[0], gp.NextPlotData.YBoundsCond[0], true, 0); - y[1] = AxisState(plot.YAxis[1], gp.NextPlotData.HasYBounds[1], gp.NextPlotData.YBoundsCond[1], - HasFlag(plot.Flags, ImPlotFlags_Y2Axis), y[0].present_so_far); - y[2] = AxisState(plot.YAxis[2], gp.NextPlotData.HasYBounds[2], gp.NextPlotData.YBoundsCond[2], - HasFlag(plot.Flags, ImPlotFlags_Y3Axis), y[1].present_so_far); + y[0] = AxisState(plot.YAxis[0], gp.NextPlotData.HasYRange[0], gp.NextPlotData.YRangeCond[0], true, 0); + y[1] = AxisState(plot.YAxis[1], gp.NextPlotData.HasYRange[1], gp.NextPlotData.YRangeCond[1], + HasFlag(plot.Flags, ImPlotFlags_YAxis2), y[0].present_so_far); + y[2] = AxisState(plot.YAxis[2], gp.NextPlotData.HasYRange[2], gp.NextPlotData.YRangeCond[2], + HasFlag(plot.Flags, ImPlotFlags_YAxis3), y[1].present_so_far); const bool lock_plot = x.lock && y[0].lock && y[1].lock && y[2].lock; const bool any_y_locked = y[0].lock || y[1].lock || y[2].lock; @@ -1413,10 +1451,14 @@ void EndPlot() { PushClipRect(gp.BB_Grid.Min, gp.BB_Frame.Max, true); // render ticks + PushPlotClipRect(); if (HasFlag(plot.XAxis.Flags, ImAxisFlags_TickMarks)) { for (ImTick &xt : gp.XTicks) DrawList.AddLine({xt.PixelPos, gp.BB_Grid.Max.y},{xt.PixelPos, gp.BB_Grid.Max.y - (xt.Major ? 10.0f : 5.0f)}, gp.Col_Border, 1); } + PopPlotClipRect(); + + PushClipRect(gp.BB_Grid.Min, {gp.BB_Frame.Max.x, gp.BB_Grid.Max.y}, true); int axis_count = 0; for (int i = 0; i < MAX_Y_AXES; i++) { if (!y[i].present) { continue; } @@ -1425,7 +1467,7 @@ void EndPlot() { if (!HasFlag(plot.YAxis[i].Flags, ImAxisFlags_TickMarks)) { continue; } float x_start = gp.AxisLabelReference[i]; - float direction = (i == 0) ? 1.0 : -1.0; + float direction = (i == 0) ? 1.0f : -1.0f; bool no_major = axis_count >= 3; for (ImTick &yt : gp.YTicks[i]) { @@ -1446,6 +1488,9 @@ void EndPlot() { } } + PopClipRect(); + + PushPlotClipRect(); // render selection/query if (plot.Selecting) { ImRect select_bb(ImMin(IO.MousePos, plot.SelectStart), ImMax(IO.MousePos, plot.SelectStart)); @@ -1568,18 +1613,18 @@ void EndPlot() { BufferWriter writer(buffer, sizeof(buffer)); writer.Write("%.2f,%.2f", gp.LastMousePos[0].x, gp.LastMousePos[0].y); - if (HasFlag(plot.Flags, ImPlotFlags_Y2Axis)) { - writer.Write(", (%.2f)", gp.LastMousePos[1].y); + if (HasFlag(plot.Flags, ImPlotFlags_YAxis2)) { + writer.Write(",(%.2f)", gp.LastMousePos[1].y); } - if (HasFlag(plot.Flags, ImPlotFlags_Y3Axis)) { - writer.Write(", (%.2f)", gp.LastMousePos[2].y); + if (HasFlag(plot.Flags, ImPlotFlags_YAxis3)) { + writer.Write(",(%.2f)", gp.LastMousePos[2].y); } ImVec2 size = CalcTextSize(buffer); ImVec2 pos = gp.BB_Grid.Max - size - ImVec2(5, 5); DrawList.AddText(pos, gp.Col_Txt, buffer); } - PopClipRect(); + PopPlotClipRect(); // render border DrawList.AddRect(gp.BB_Grid.Min, gp.BB_Grid.Max, gp.Col_Border); @@ -1630,24 +1675,24 @@ void EndPlot() { // MISC API //----------------------------------------------------------------------------- -void SetNextPlotBounds(float x_min, float x_max, float y_min, float y_max, ImGuiCond cond) { - SetNextPlotBoundsX(x_min, x_max, cond); - SetNextPlotBoundsY(y_min, y_max, cond); +void SetNextPlotLimits(float x_min, float x_max, float y_min, float y_max, ImGuiCond cond) { + SetNextPlotLimitsX(x_min, x_max, cond); + SetNextPlotLimitsY(y_min, y_max, cond); } -void SetNextPlotBoundsX(float x_min, float x_max, ImGuiCond cond) { +void SetNextPlotLimitsX(float x_min, float x_max, ImGuiCond cond) { IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags. - gp.NextPlotData.HasXBounds = true; - gp.NextPlotData.XBoundsCond = cond; + gp.NextPlotData.HasXRange = true; + gp.NextPlotData.XRangeCond = cond; gp.NextPlotData.X.Min = x_min; gp.NextPlotData.X.Max = x_max; } -void SetNextPlotBoundsY(float y_min, float y_max, ImGuiCond cond, int y_axis) { +void SetNextPlotLimitsY(float y_min, float y_max, ImGuiCond cond, int y_axis) { 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(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags. - gp.NextPlotData.HasYBounds[y_axis] = true; - gp.NextPlotData.YBoundsCond[y_axis] = cond; + gp.NextPlotData.HasYRange[y_axis] = true; + gp.NextPlotData.YRangeCond[y_axis] = cond; gp.NextPlotData.Y[y_axis].Min = y_min; gp.NextPlotData.Y[y_axis].Max = y_max; } @@ -1689,16 +1734,16 @@ ImVec2 GetPlotMousePos(int y_axis_in) { } -ImPlotBounds GetPlotBounds(int y_axis_in) { +ImPlotLimits GetPlotLimits(int y_axis_in) { 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(gp.CurrentPlot != NULL, "GetPlotBounds() Needs to be called between BeginPlot() and EndPlot()!"); + 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; ImPlot& plot = *gp.CurrentPlot; - ImPlotBounds bounds; - bounds.X = plot.XAxis.Range; - bounds.Y = plot.YAxis[y_axis].Range; - return bounds; + ImPlotLimits limits; + limits.X = plot.XAxis.Range; + limits.Y = plot.YAxis[y_axis].Range; + return limits; } bool IsPlotQueried() { @@ -1706,7 +1751,7 @@ bool IsPlotQueried() { return gp.CurrentPlot->Queried; } -ImPlotBounds GetPlotQuery(int y_axis_in) { +ImPlotLimits GetPlotQuery(int y_axis_in) { 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(gp.CurrentPlot != NULL, "GetPlotQuery() Needs to be called between BeginPlot() and EndPlot()!"); ImPlot& plot = *gp.CurrentPlot; @@ -1716,12 +1761,11 @@ ImPlotBounds GetPlotQuery(int y_axis_in) { ImVec2 p1 = PixelsToPlot(plot.QueryRect.Min + gp.BB_Grid.Min, y_axis); ImVec2 p2 = PixelsToPlot(plot.QueryRect.Max + gp.BB_Grid.Min, y_axis); - ImPlotBounds result; + ImPlotLimits result; result.X.Min = ImMin(p1.x, p2.x); result.X.Max = ImMax(p1.x, p2.x); result.Y.Min = ImMin(p1.y, p2.y); result.Y.Max = ImMax(p1.y, p2.y); - return result; } @@ -2520,10 +2564,10 @@ inline void PlotDigitalEx(const char* label_id, Getter getter, int count, int of if (count > 1 && rend_line) { // const float mx = (gp.PixelRange[ax].Max.x - gp.PixelRange[ax].Min.x) / gp.CurrentPlot->XAxis.Range.Size(); - int pixY_0 = line_weight; - int pixY_1 = gp.Style.DigitalBitHeight; - int pixY_Offset = 20;//20 pixel from bottom due to mouse cursor label - int pixY_chOffset = pixY_1 + 3; //3 pixels between channels + float pixY_0 = line_weight; + float pixY_1 = gp.Style.DigitalBitHeight; + float pixY_Offset = 20;//20 pixel from bottom due to mouse cursor label + float pixY_chOffset = pixY_1 + 3; //3 pixels between channels ImVec2 pMin, pMax; float y0 = (gp.PixelRange[ax].Min.y) + ((-pixY_chOffset * gp.DigitalPlotItemCnt) - pixY_0 - pixY_Offset); float y1 = (gp.PixelRange[ax].Min.y) + ((-pixY_chOffset * gp.DigitalPlotItemCnt) - pixY_1 - pixY_Offset); @@ -2554,7 +2598,7 @@ inline void PlotDigitalEx(const char* label_id, Getter getter, int count, int of //plot a rectangle that extends up to x2 with y1 height if ((pMax.x > pMin.x) && (!cull || gp.BB_Grid.Contains(pMin) || gp.BB_Grid.Contains(pMax))) { ImVec4 colAlpha = item->Color; - colAlpha.w = item->Highlight ? 1.0 : 0.9; + colAlpha.w = item->Highlight ? 1.0f : 0.9f; DrawList.AddRectFilled(pMin, pMax, GetColorU32(colAlpha)); } } diff --git a/implot.h b/implot.h index bbe6c44..4911094 100644 --- a/implot.h +++ b/implot.h @@ -20,7 +20,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -// ImPlot v0.1 WIP +// ImPlot v0.2 WIP #pragma once #include @@ -41,13 +41,14 @@ enum ImPlotFlags_ { ImPlotFlags_Legend = 1 << 1, // a legend will be displayed in the top-left ImPlotFlags_Highlight = 1 << 2, // plot items will be highlighted when their legend entry is hovered ImPlotFlags_Selection = 1 << 3, // the user will be able to box-select with right-mouse - ImPlotFlags_ContextMenu = 1 << 4, // the user will be able to open a context menu with double-right click - ImPlotFlags_Crosshairs = 1 << 5, // the default mouse cursor will be replaced with a crosshair when hovered - ImPlotFlags_CullData = 1 << 6, // plot data outside the plot area will be culled from rendering - ImPlotFlags_AntiAliased = 1 << 7, // lines and fills will be anti-aliased (not recommended) - ImPlotFlags_NoChild = 1 << 8, // a child window region will not be used to capture mouse scroll (can boost performance for single ImGui window applications) - ImPlotFlags_Y2Axis = 1 << 9, // enable a second y axis - ImPlotFlags_Y3Axis = 1 << 10, // enable a third y axis + ImPlotFlags_Query = 1 << 4, // the user will be able to draw query rects with middle-mouse + ImPlotFlags_ContextMenu = 1 << 5, // the user will be able to open a context menu with double-right click + ImPlotFlags_Crosshairs = 1 << 6, // the default mouse cursor will be replaced with a crosshair when hovered + ImPlotFlags_CullData = 1 << 7, // plot data outside the plot area will be culled from rendering + ImPlotFlags_AntiAliased = 1 << 8, // lines and fills will be anti-aliased (not recommended) + ImPlotFlags_NoChild = 1 << 9, // a child window region will not be used to capture mouse scroll (can boost performance for single ImGui window applications) + ImPlotFlags_YAxis2 = 1 << 10, // enable a 2nd y axis + ImPlotFlags_YAxis3 = 1 << 11, // enable a 3rd y axis ImPlotFlags_Default = ImPlotFlags_MousePos | ImPlotFlags_Legend | ImPlotFlags_Highlight | ImPlotFlags_Selection | ImPlotFlags_ContextMenu | ImPlotFlags_CullData }; @@ -63,7 +64,7 @@ enum ImAxisFlags_ { ImAxisFlags_LogScale = 1 << 7, // a logartithmic (base 10) axis scale will be used ImAxisFlags_Scientific = 1 << 8, // scientific notation will be used for tick labels if displayed (WIP, not very good yet) ImAxisFlags_Default = ImAxisFlags_GridLines | ImAxisFlags_TickMarks | ImAxisFlags_TickLabels | ImAxisFlags_Adaptive, - ImAxisFlags_Auxiliary_Default = ImAxisFlags_Default & ~ImAxisFlags_GridLines, + ImAxisFlags_Auxiliary = ImAxisFlags_Default & ~ImAxisFlags_GridLines, }; // Plot styling colors @@ -76,15 +77,16 @@ enum ImPlotCol_ { 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_Text) - ImPlotCol_XAxis, // x-axis grid/label color (defaults to ImGuiCol_Text) - ImPlotCol_YAxis, // y-axis grid/label color (defaults to ImGuiCol_Text) - ImPlotCol_Y2Axis, // y2-axis grid/label color (defaults to ImGuiCol_Text) - ImPlotCol_Y3Axis, // y3-axis grid/label color (defaults to ImGuiCol_Text) + ImPlotCol_XAxis, // x-axis grid/label color (defaults to 25% ImGuiCol_Text) + ImPlotCol_YAxis, // y-axis grid/label color (defaults to 25% ImGuiCol_Text) + ImPlotCol_YAxis2, // 2nd y-axis grid/label color (defaults to 25% ImGuiCol_Text) + ImPlotCol_YAxis3, // 3rd y-axis grid/label color (defaults to 25% ImGuiCol_Text) ImPlotCol_Selection, // box-selection color (defaults to yellow) ImPlotCol_Query, // box-query color (defaults to green) ImPlotCol_COUNT }; +// Plot styling variables enum ImPlotStyleVar_ { ImPlotStyleVar_LineWeight, // float, line weight in pixels ImPlotStyleVar_Marker, // int, marker specification @@ -111,17 +113,18 @@ enum ImMarker_ { ImMarker_Asterisk = 1 << 10, // a asterisk marker will be rendered at each point (not filled) }; +// A range defined by a min/max value. Used for plot axes ranges. struct ImPlotRange { float Min, Max; ImPlotRange(); - bool Contains(float) const; + bool Contains(float value) const; float Size() const; }; -/// Plot range utility struct -struct ImPlotBounds { +// Combination of two ranges for X and Y axes. +struct ImPlotLimits { ImPlotRange X, Y; - ImPlotBounds(); + ImPlotLimits(); bool Contains(const ImVec2& p) const; }; @@ -148,17 +151,16 @@ namespace ImGui { // 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. Axis flags are -// only set ONCE during the first call to BeginPlot. +// 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, - const ImVec2& size = ImVec2(-1,-1), - ImPlotFlags flags = ImPlotFlags_Default, - ImAxisFlags x_flags = ImAxisFlags_Default, - ImAxisFlags y_flags = ImAxisFlags_Default, - ImAxisFlags y2_flags = ImAxisFlags_Auxiliary_Default, - ImAxisFlags y3_flags = ImAxisFlags_Auxiliary_Default); + const char* x_label = NULL, + const char* y_label = NULL, + const ImVec2& size = ImVec2(-1,-1), + ImPlotFlags flags = ImPlotFlags_Default, + ImAxisFlags x_flags = ImAxisFlags_Default, + ImAxisFlags y_flags = ImAxisFlags_Default, + ImAxisFlags y2_flags = ImAxisFlags_Auxiliary, + ImAxisFlags y3_flags = ImAxisFlags_Auxiliary); // Only call EndPlot() if BeginPlot() returns true! Typically called at the end // of an if statement conditioned on BeginPlot(). void EndPlot(); @@ -167,7 +169,7 @@ void EndPlot(); // Plot Items //----------------------------------------------------------------------------- -// Plots a standard 2D line and/or scatter plot . +// Plots a standard 2D line and/or scatter plot. void Plot(const char* label_id, const float* values, int count, int offset = 0, int stride = sizeof(float)); void Plot(const char* label_id, const float* xs, const float* ys, int count, int offset = 0, int stride = sizeof(float)); void Plot(const char* label_id, const ImVec2* data, int count, int offset = 0); @@ -201,11 +203,11 @@ bool IsPlotHovered(); /// Returns the mouse position in x,y coordinates of the current or most recent plot. A negative y_axis uses the current value of SetPlotYAxis (0 initially). ImVec2 GetPlotMousePos(int y_axis = -1); /// Returns the current or most recent plot axis range. A negative y_axis uses the current value of SetPlotYAxis (0 initially). -ImPlotBounds GetPlotBounds(int y_axis = -1); +ImPlotLimits GetPlotLimits(int y_axis = -1); /// Returns true if the current or most recent plot is being queried. bool IsPlotQueried(); /// Returns the current or most recent plot query bounds. -ImPlotBounds GetPlotQuery(int y_axis = -1); +ImPlotLimits GetPlotQuery(int y_axis = -1); //----------------------------------------------------------------------------- // Plot Styling @@ -237,15 +239,15 @@ void PopPlotStyleVar(int count = 1); // Plot Utils //----------------------------------------------------------------------------- -/// Set the axes ranges of the next plot. Call right before BeginPlot(). If ImGuiCond_Always is used, the axes will be locked. -void SetNextPlotBounds(float x_min, float x_max, float y_min, float y_max, ImGuiCond cond = ImGuiCond_Once); -/// Set the X axis range of the next plot. Call right before BeginPlot(). If ImGuiCond_Always is used, the axis will be locked. -void SetNextPlotBoundsX(float x_min, float x_max, ImGuiCond cond = ImGuiCond_Once); -/// Set the Y axis range of the next plot. Call right before BeginPlot(). If ImGuiCond_Always is used, the axis will be locked. -void SetNextPlotBoundsY(float y_min, float y_max, ImGuiCond cond = ImGuiCond_Once, int y_axis = 0); +/// Set the axes range limits of the next plot. Call right before BeginPlot(). If ImGuiCond_Always is used, the axes limits will be locked. +void SetNextPlotLimits(float x_min, float x_max, float y_min, float y_max, ImGuiCond cond = ImGuiCond_Once); +/// Set the X axis range limits of the next plot. Call right before BeginPlot(). If ImGuiCond_Always is used, the axis limits will be locked. +void SetNextPlotLimitsX(float x_min, float x_max, ImGuiCond cond = ImGuiCond_Once); +/// Set the Y axis range limits of the next plot. Call right before BeginPlot(). If ImGuiCond_Always is used, the axis limits will be locked. +void SetNextPlotLimitsY(float y_min, float y_max, ImGuiCond cond = ImGuiCond_Once, int y_axis = 0); -/// Select which Y axis will be used for subsequent plot elements. The default is '0', or the first Y axis. -void SetPlotYAxis(int); +/// Select which Y axis will be used for subsequent plot elements. The default is '0', or the first Y axis. +void SetPlotYAxis(int y_axis); // Get the current Plot position (top-left) in pixels. ImVec2 GetPlotPos(); diff --git a/implot_demo.cpp b/implot_demo.cpp index 948efdd..55baebb 100644 --- a/implot_demo.cpp +++ b/implot_demo.cpp @@ -20,7 +20,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -// ImPlot v0.1 WIP +// ImPlot v0.2 WIP #ifdef _MSC_VER #pragma warning (disable: 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen @@ -95,7 +95,7 @@ void ShowImPlotDemoWindow(bool* p_open) { ImGui::SetNextWindowPos(ImVec2(50, 50), ImGuiCond_FirstUseEver); ImGui::SetNextWindowSize(ImVec2(520, 750), ImGuiCond_FirstUseEver); ImGui::Begin("ImPlot Demo", p_open); - ImGui::Text("ImPlot says hello. (0.1 WIP)"); + ImGui::Text("ImPlot says hello. (0.2 WIP)"); if (ImGui::CollapsingHeader("Help")) { ImGui::Text("USER GUIDE:"); ImGui::BulletText("Left click and drag within the plot area to pan X and Y axes."); @@ -112,11 +112,6 @@ void ShowImPlotDemoWindow(bool* p_open) { ImGui::BulletText("Hold Shift to expand box selection vertically."); ImGui::BulletText("Left click while box selecting to cancel the selection."); ImGui::Unindent(); - ImGui::BulletText("Middle click (or Ctrl + right click) and drag to create a query range."); - ImGui::Indent(); - ImGui::BulletText("Hold Alt to expand query horizontally."); - ImGui::BulletText("Hold Shift to expand query vertically."); - ImGui::Unindent(); ImGui::BulletText("Double left click to fit all visible data."); ImGui::Indent(); ImGui::BulletText("Double left click on an axis to fit the individual axis."); @@ -176,9 +171,9 @@ void ShowImPlotDemoWindow(bool* p_open) { static bool horz = false; ImGui::Checkbox("Horizontal",&horz); if (horz) - ImGui::SetNextPlotBounds(0, 110, -0.5f, 9.5f, ImGuiCond_Always); + ImGui::SetNextPlotLimits(0, 110, -0.5f, 9.5f, ImGuiCond_Always); else - ImGui::SetNextPlotBounds(-0.5f, 9.5f, 0, 110, ImGuiCond_Always); + ImGui::SetNextPlotLimits(-0.5f, 9.5f, 0, 110, ImGuiCond_Always); if (ImGui::BeginPlot("Bar Plot", horz ? "Score": "Student", horz ? "Student" : "Score", {-1, 300})) { static float midtm[10] = {83, 67, 23, 89, 83, 78, 91, 82, 85, 90}; static float final[10] = {80, 62, 56, 99, 55, 78, 88, 78, 90, 100}; @@ -203,7 +198,7 @@ void ShowImPlotDemoWindow(bool* p_open) { float bar[5] = {1,2,5,3,4}; float err1[5] = {0.2f, 0.4f, 0.2f, 0.6f, 0.4f}; float err2[5] = {0.4f, 0.2f, 0.4f, 0.8f, 0.6f}; - ImGui::SetNextPlotBounds(0, 6, 0, 10); + ImGui::SetNextPlotLimits(0, 6, 0, 10); if (ImGui::BeginPlot("##ErrorBars",NULL,NULL,ImVec2(-1,300))) { ImGui::PlotBar("Bar", xs, bar, 5, 0.5f); @@ -227,7 +222,7 @@ void ShowImPlotDemoWindow(bool* p_open) { ImVec2 center(0.5f,0.5f); // in plot units, not pixels float radius = 0.4f; // in plot units, not pixels - SetNextPlotBounds(0,1,0,1,ImGuiCond_Always); + SetNextPlotLimits(0,1,0,1,ImGuiCond_Always); if (ImGui::BeginPlot("##Pie1", NULL, NULL, ImVec2(250,250), ImPlotFlags_Legend, 0, 0)) { ImGui::PlotPieChart(labels1, pre_normalized, 4, center, radius); ImGui::EndPlot(); @@ -242,7 +237,7 @@ void ShowImPlotDemoWindow(bool* p_open) { {0.7412f, 0.0f, 0.1490f, 1.0f}, }; ImGui::SetPlotPalette(YlOrRd, 5); - SetNextPlotBounds(0,1,0,1,ImGuiCond_Always); + SetNextPlotLimits(0,1,0,1,ImGuiCond_Always); static const char* labels2[] = {"One","Two","Three","Four","Five"}; static float not_normalized[] = {1,2,3,4,5}; if (ImGui::BeginPlot("##Pie2", NULL, NULL, ImVec2(250,250), ImPlotFlags_Legend, 0, 0)) { @@ -268,14 +263,14 @@ void ShowImPlotDemoWindow(bool* p_open) { sdata2.AddPoint(t, mouse.y * 0.0005f); rdata2.AddPoint(t, mouse.y * 0.0005f); } - ImGui::SetNextPlotBoundsX(t - 10, t, paused ? ImGuiCond_Once : ImGuiCond_Always); + ImGui::SetNextPlotLimitsX(t - 10, t, paused ? ImGuiCond_Once : ImGuiCond_Always); static int rt_axis = ImAxisFlags_Default & ~ImAxisFlags_TickLabels; if (ImGui::BeginPlot("##Scrolling", NULL, NULL, {-1,150}, ImPlotFlags_Default, rt_axis, rt_axis)) { ImGui::Plot("Data 1", &sdata1.Data[0].x, &sdata1.Data[0].y, sdata1.Data.size(), sdata1.Offset, 2 * sizeof(float)); ImGui::Plot("Data 2", &sdata2.Data[0].x, &sdata2.Data[0].y, sdata2.Data.size(), sdata2.Offset, 2 * sizeof(float)); ImGui::EndPlot(); } - ImGui::SetNextPlotBoundsX(0, 10, ImGuiCond_Always); + ImGui::SetNextPlotLimitsX(0, 10, ImGuiCond_Always); if (ImGui::BeginPlot("##Rolling", NULL, NULL, {-1,150}, ImPlotFlags_Default, rt_axis, rt_axis)) { ImGui::Plot("Data 1", &rdata1.Data[0].x, &rdata1.Data[0].y, rdata1.Data.size(), 0, 2 * sizeof(float)); ImGui::Plot("Data 2", &rdata2.Data[0].x, &rdata2.Data[0].y, rdata2.Data.size(), 0, 2 * sizeof(float)); @@ -285,7 +280,7 @@ void ShowImPlotDemoWindow(bool* p_open) { //------------------------------------------------------------------------- if (ImGui::CollapsingHeader("Markers and Labels")) { - ImGui::SetNextPlotBounds(0, 10, 0, 12); + ImGui::SetNextPlotLimits(0, 10, 0, 12); if (ImGui::BeginPlot("##MarkerStyles", NULL, NULL, ImVec2(-1,300), 0, 0, 0)) { float xs[2] = {1,4}; float ys[2] = {10,11}; @@ -369,7 +364,7 @@ void ShowImPlotDemoWindow(bool* p_open) { ys2[i] = log(xs[i]); ys3[i] = pow(10.0f, xs[i]); } - ImGui::SetNextPlotBounds(0.1f, 100, 0, 10); + ImGui::SetNextPlotLimits(0.1f, 100, 0, 10); if (ImGui::BeginPlot("Log Plot", NULL, NULL, ImVec2(-1,300), ImPlotFlags_Default, ImAxisFlags_Default | ImAxisFlags_LogScale )) { ImGui::Plot("f(x) = x", xs, xs, 1001); ImGui::Plot("f(x) = sin(x)+1", xs, ys1, 1001); @@ -379,25 +374,43 @@ void ShowImPlotDemoWindow(bool* p_open) { } } //------------------------------------------------------------------------- - if (ImGui::CollapsingHeader("Multiple Y Axes")) { + if (ImGui::CollapsingHeader("Multiple Y-Axes")) { + static ImVec4 txt_col = ImGui::GetStyle().Colors[ImGuiCol_Text]; + txt_col.w = 0.25f; + static ImVec4 y1_col = txt_col; + static ImVec4 y2_col = txt_col; + static ImVec4 y3_col = txt_col; + static float xs[1001], xs2[1001], ys1[1001], ys2[1001], ys3[1001]; static bool y2_axis = true; static bool y3_axis = false; - + ImGui::Checkbox("Y-Axis 2", &y2_axis); + ImGui::SameLine(); + ImGui::Checkbox("Y-Axis 3", &y3_axis); + ImGui::SameLine(); + ImGui::ColorEdit4("##Col1", &y1_col.x, ImGuiColorEditFlags_NoInputs); + ImGui::SameLine(); + ImGui::ColorEdit4("##Col2", &y2_col.x, ImGuiColorEditFlags_NoInputs); + ImGui::SameLine(); + ImGui::ColorEdit4("##Col3", &y3_col.x, ImGuiColorEditFlags_NoInputs); for (int i = 0; i < 1001; ++i) { xs[i] = (float)(i*0.1f); ys1[i] = sin(xs[i]) * 3 + 1; - ys2[i] = cos(xs[i]) * 0.2 + 0.5; - ys3[i] = sin(xs[i]+.5) * 100 + 200; - xs2[i] = xs[i] + 10.0; + ys2[i] = cos(xs[i]) * 0.2f + 0.5f; + ys3[i] = sin(xs[i]+0.5f) * 100 + 200; + xs2[i] = xs[i] + 10.0f; } - ImGui::SetNextPlotBounds(0.1f, 100, 0, 10); - ImGui::SetNextPlotBoundsY(0, 1, ImGuiCond_Once, 1); - ImGui::SetNextPlotBoundsY(0, 300, ImGuiCond_Once, 2); + ImGui::SetNextPlotLimits(0.1f, 100, 0, 10); + ImGui::SetNextPlotLimitsY(0, 1, ImGuiCond_Once, 1); + ImGui::SetNextPlotLimitsY(0, 300, ImGuiCond_Once, 2); + ImGui::PushPlotColor(ImPlotCol_YAxis, y1_col); + ImGui::PushPlotColor(ImPlotCol_YAxis2, y2_col); + ImGui::PushPlotColor(ImPlotCol_YAxis3, y3_col); + if (ImGui::BeginPlot("Multi-Axis Plot", NULL, NULL, ImVec2(-1,300), ImPlotFlags_Default | - (y2_axis ? ImPlotFlags_Y2Axis : 0) | - (y3_axis ? ImPlotFlags_Y3Axis : 0))) { + (y2_axis ? ImPlotFlags_YAxis2 : 0) | + (y3_axis ? ImPlotFlags_YAxis3 : 0))) { ImGui::Plot("f(x) = x", xs, xs, 1001); ImGui::Plot("f(x) = sin(x)*3+1", xs, ys1, 1001); @@ -413,18 +426,20 @@ void ShowImPlotDemoWindow(bool* p_open) { ImGui::EndPlot(); } - ImGui::Checkbox("Y2 Axis", &y2_axis); - ImGui::SameLine(); - ImGui::Checkbox("Y3 Axis", &y3_axis); + ImGui::PopPlotColor(3); } //------------------------------------------------------------------------- if (ImGui::CollapsingHeader("Querying")) { ImGui::BulletText("Ctrl + click in the plot area to draw points."); - ImGui::BulletText("Middle click (or Ctrl + right click) and drag to query points."); - ImGui::BulletText("Hold the Alt and/or Shift keys to expand the query range."); + ImGui::BulletText("Middle click (or Ctrl + right click) and drag to create a query rect."); + ImGui::Indent(); + ImGui::BulletText("Hold Alt to expand query horizontally."); + ImGui::BulletText("Hold Shift to expand query vertically."); + ImGui::BulletText("The query rect can be dragged after it's created."); + ImGui::Unindent(); static ImVector data; - ImPlotBounds range, query; - if (ImGui::BeginPlot("##Drawing", NULL, NULL, ImVec2(-1,300), ImPlotFlags_Default, ImAxisFlags_GridLines, ImAxisFlags_GridLines)) { + ImPlotLimits range, query; + if (ImGui::BeginPlot("##Drawing", NULL, NULL, ImVec2(-1,300), ImPlotFlags_Default | ImPlotFlags_Query, ImAxisFlags_GridLines, ImAxisFlags_GridLines)) { if (ImGui::IsPlotHovered() && ImGui::IsMouseClicked(0) && ImGui::GetIO().KeyCtrl) data.push_back(ImGui::GetPlotMousePos()); ImGui::PushPlotStyleVar(ImPlotStyleVar_LineWeight, 0); @@ -432,7 +447,7 @@ void ShowImPlotDemoWindow(bool* p_open) { if (data.size() > 0) ImGui::Plot("Points", &data[0].x, &data[0].y, data.size(), 0, 2 * sizeof(float)); if (ImGui::IsPlotQueried() && data.size() > 0) { - ImPlotBounds range = ImGui::GetPlotQuery(); + ImPlotLimits range = ImGui::GetPlotQuery(); int cnt = 0; ImVec2 avg; for (int i = 0; i < data.size(); ++i) { @@ -449,12 +464,12 @@ void ShowImPlotDemoWindow(bool* p_open) { } } ImGui::PopPlotStyleVar(2); - range = ImGui::GetPlotBounds(); + range = ImGui::GetPlotLimits(); query = ImGui::GetPlotQuery(); ImGui::EndPlot(); } - ImGui::Text("The current plot range is: [%g,%g,%g,%g]", range.X.Min, range.X.Max, range.Y.Min, range.Y.Max); - ImGui::Text("The current query range is: [%g,%g,%g,%g]", query.X.Min, query.X.Max, query.Y.Min, query.Y.Max); + ImGui::Text("The current plot limits are: [%g,%g,%g,%g]", range.X.Min, range.X.Max, range.Y.Min, range.Y.Max); + ImGui::Text("The current query limits are: [%g,%g,%g,%g]", query.X.Min, query.X.Max, query.Y.Min, query.Y.Max); } //------------------------------------------------------------------------- if (ImGui::CollapsingHeader("Views")) { @@ -468,24 +483,23 @@ void ShowImPlotDemoWindow(bool* p_open) { for (size_t i = 0; i < 512; ++i) { const float t = i / sampling_freq; x_data[i] = t; - const float arg = 2 * 3.14 * freq * t; + const float arg = 2 * 3.14f * freq * t; y_data1[i] = sin(arg); - y_data2[i] = y_data1[i] * -0.6 + sin(2 * arg) * 0.4; - y_data3[i] = y_data2[i] * -0.6 + sin(3 * arg) * 0.4; + y_data2[i] = y_data1[i] * -0.6f + sin(2 * arg) * 0.4f; + y_data3[i] = y_data2[i] * -0.6f + sin(3 * arg) * 0.4f; } - ImGui::BulletText("Query the first plot to render a subview in the second plot."); - ImGui::BulletText("Toggle \"Pixel Query\" in the context menu and then pan the plot."); - ImGui::SetNextPlotBounds(0,0.01f,-1,1); + ImGui::BulletText("Query the first plot to render a subview in the second plot (see above for controls)."); + ImGui::SetNextPlotLimits(0,0.01f,-1,1); ImAxisFlags flgs = ImAxisFlags_Default & ~ImAxisFlags_TickLabels; - ImPlotBounds query; - if (ImGui::BeginPlot("##View1",NULL,NULL,ImVec2(-1,150), ImPlotFlags_Default, flgs, flgs)) { + ImPlotLimits query; + if (ImGui::BeginPlot("##View1",NULL,NULL,ImVec2(-1,150), ImPlotFlags_Default | ImPlotFlags_Query, flgs, flgs)) { ImGui::Plot("Signal 1", x_data, y_data1, 512); ImGui::Plot("Signal 2", x_data, y_data2, 512); ImGui::Plot("Signal 3", x_data, y_data3, 512); query = ImGui::GetPlotQuery(); ImGui::EndPlot(); } - ImGui::SetNextPlotBounds(query.X.Min, query.X.Max, query.Y.Min, query.Y.Max, ImGuiCond_Always); + ImGui::SetNextPlotLimits(query.X.Min, query.X.Max, query.Y.Min, query.Y.Max, ImGuiCond_Always); if (ImGui::BeginPlot("##View2",NULL,NULL,ImVec2(-1,150), 0, 0, 0)) { ImGui::Plot("Signal 1", x_data, y_data1, 512); ImGui::Plot("Signal 2", x_data, y_data2, 512); @@ -493,12 +507,9 @@ void ShowImPlotDemoWindow(bool* p_open) { ImGui::EndPlot(); } } - - - //------------------------------------------------------------------------- if (ImGui::CollapsingHeader("Drag and Drop")) { - srand(10000000 * ImGui::GetTime()); + srand((int)(10000000 * ImGui::GetTime())); static bool paused = false; static bool init = true; static ScrollingData data[10]; @@ -543,7 +554,7 @@ void ShowImPlotDemoWindow(bool* p_open) { data[i].Data.back().y + (0.005f + 0.0002f * (float)rand() / float(RAND_MAX)) * (-1 + 2 * (float)rand() / float(RAND_MAX))); } } - ImGui::SetNextPlotBoundsX(t - 10, t, paused ? ImGuiCond_Once : ImGuiCond_Always); + ImGui::SetNextPlotLimitsX(t - 10, t, paused ? ImGuiCond_Once : ImGuiCond_Always); if (ImGui::BeginPlot("##DND", NULL, NULL, ImVec2(-1,300), ImPlotFlags_Default)) { for (int i = 0; i < 10; ++i) { if (show[i]) { @@ -644,8 +655,8 @@ void ShowImPlotDemoWindow(bool* p_open) { if (showAnalog[i]) dataAnalog[i].AddPoint(t, sin(2*t) - cos(2*t)); } - ImGui::SetNextPlotBoundsY(-1, 1); - ImGui::SetNextPlotBoundsX(t - 10.0f, t, paused ? ImGuiCond_Once : ImGuiCond_Always); + ImGui::SetNextPlotLimitsY(-1, 1); + ImGui::SetNextPlotLimitsX(t - 10.0f, t, paused ? ImGuiCond_Once : ImGuiCond_Always); if (ImGui::BeginPlot("##Digital", NULL, NULL, ImVec2(-1,300), ImPlotFlags_Default)) { for (int i = 0; i < K_PLOT_DIGITAL_CH_COUNT; ++i) { if (showDigital[i]) { @@ -692,7 +703,7 @@ void ShowImPlotDemoWindow(bool* p_open) { ImGui::PushPlotColor(ImPlotCol_XAxis, IM_COL32(192, 192, 192, 192)); ImGui::PushPlotColor(ImPlotCol_YAxis, IM_COL32(192, 192, 192, 192)); ImGui::PushPlotStyleVar(ImPlotStyleVar_LineWeight, 2); - ImGui::SetNextPlotBounds(-0.5f, 9.5f, -0.5f, 9.5f); + ImGui::SetNextPlotLimits(-0.5f, 9.5f, -0.5f, 9.5f); if (ImGui::BeginPlot("##Custom", NULL, NULL, {-1,300}, ImPlotFlags_Default & ~ImPlotFlags_Legend, 0)) { float lin[10] = {8,8,9,7,8,8,8,9,7,8}; float bar[10] = {1,2,5,3,4,1,2,5,3,4}; @@ -727,7 +738,7 @@ void ShowImPlotDemoWindow(bool* p_open) { static BenchmarkItem items[n_items]; ImGui::BulletText("Make sure VSync is disabled."); ImGui::BulletText("%d lines with %d points each @ %.3f FPS.",n_items,1000,ImGui::GetIO().Framerate); - SetNextPlotBounds(0,1,0,1, ImGuiCond_Always); + SetNextPlotLimits(0,1,0,1, ImGuiCond_Always); if (ImGui::BeginPlot("##Bench",NULL,NULL,{-1,300},ImPlotFlags_Default | ImPlotFlags_NoChild)) { char buff[16]; for (int i = 0; i < 100; ++i) {