From 494b9eb61d6d84f9dd8fb4c9a8d19e6832edc876 Mon Sep 17 00:00:00 2001 From: ozlb Date: Sat, 9 May 2020 06:54:16 +0200 Subject: [PATCH 01/11] PlotDigital multi level Plot digital channels as float (only positive values) --- implot.cpp | 34 ++++++++++--------- implot.h | 8 +++-- implot_demo.cpp | 88 +++++++++++++++++++------------------------------ 3 files changed, 58 insertions(+), 72 deletions(-) diff --git a/implot.cpp b/implot.cpp index 57bf432..0a89831 100644 --- a/implot.cpp +++ b/implot.cpp @@ -49,7 +49,8 @@ ImPlotStyle::ImPlotStyle() { MarkerWeight = 1; ErrorBarSize = 5; ErrorBarWeight = 1.5; - DigitalBitHeight = 7; + DigitalBitHeight = 8; + DigitalBitGap = 4; Colors[ImPlotCol_Line] = IM_COL_AUTO; Colors[ImPlotCol_Fill] = IM_COL_AUTO; @@ -330,6 +331,7 @@ struct ImPlotContext { ImNextPlotData NextPlotData; // Digital plot item count int DigitalPlotItemCnt; + int DigitalPlotOffset; }; /// Global plot context @@ -1056,6 +1058,7 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons gp.LegendLabels.Buf.resize(0); // reset digital plot items count gp.DigitalPlotItemCnt = 0; + gp.DigitalPlotOffset = 0; return true; } @@ -1469,7 +1472,8 @@ static const ImPlotStyleVarInfo GPlotStyleVarInfo[] = { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImPlotStyle, MarkerWeight) }, // ImPlotStyleVar_MarkerWeight { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImPlotStyle, ErrorBarSize) }, // ImPlotStyleVar_ErrorBarSize { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImPlotStyle, ErrorBarWeight) }, // ImPlotStyleVar_ErrorBarWeight - { ImGuiDataType_S32, 1, (ImU32)IM_OFFSETOF(ImPlotStyle, DigitalBitHeight) } // ImPlotStyleVar_DigitalBitHeight + { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImPlotStyle, DigitalBitHeight) }, // ImPlotStyleVar_DigitalBitHeight + { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImPlotStyle, DigitalBitGap) } // ImPlotStyleVar_DigitalBitGap }; static const ImPlotStyleVarInfo* GetPlotStyleVarInfo(ImPlotStyleVar idx) @@ -2187,8 +2191,8 @@ void PlotPieChart(const char** label_ids, float* values, int count, const ImVec2 ImVec2 size = CalcTextSize(buffer); float angle = a0 + (a1 - a0) * 0.5f; ImVec2 pos = PlotToPixels(center.x + 0.5f * radius * cos(angle), center.y + 0.5f * radius * sin(angle)); - DrawList.AddText(pos - size * 0.5f + ImVec2(1,1), gp.Col_Bg, buffer); - DrawList.AddText(pos - size * 0.5f, GetColorU32(ImGuiCol_Text), buffer); + DrawList.AddText(pos - size * 0.5f + ImVec2(1,1), IM_COL32(0,0,0,255), buffer); + DrawList.AddText(pos - size * 0.5f, IM_COL32(255,255,255,255), buffer); } } a0 = a1; @@ -2236,31 +2240,30 @@ inline void PlotDigitalEx(const char* label_id, Getter getter, int count, int of bool cull = HasFlag(gp.CurrentPlot->Flags, ImPlotFlags_CullData); const float line_weight = item->Highlight ? gp.Style.LineWeight * 2 : gp.Style.LineWeight; - // render digital signals as "pixel bases" rectangles if (count > 1 && rend_line) { // const float mx = (gp.PixelRange.Max.x - gp.PixelRange.Min.x) / (gp.CurrentPlot->XAxis.Max - gp.CurrentPlot->XAxis.Min); - 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 - ImVec2 pMin, pMax; - float y0 = (gp.PixelRange.Min.y) + ((-pixY_chOffset * gp.DigitalPlotItemCnt) - pixY_0 - pixY_Offset); - float y1 = (gp.PixelRange.Min.y) + ((-pixY_chOffset * gp.DigitalPlotItemCnt) - pixY_1 - pixY_Offset); const int segments = count - 1; int i1 = offset; + int pixYMax = 0; for (int s = 0; s < segments; ++s) { const int i2 = (i1 + 1) % count; ImVec2 itemData1 = getter(i1); ImVec2 itemData2 = getter(i2); i1 = i2; + int pixY_0 = line_weight; + int pixY_1 = gp.Style.DigitalBitHeight * ImMax(0.0f, itemData1.y); //allow only positive values + int pixY_chPosOffset = ImMax((int)gp.Style.DigitalBitHeight, pixY_1) + gp.Style.DigitalBitGap; + pixYMax = ImMax(pixYMax, pixY_chPosOffset); + ImVec2 pMin, pMax; pMin.x = gp.PixelRange.Min.x + mx * (itemData1.x - gp.CurrentPlot->XAxis.Min); - pMin.y = (gp.PixelRange.Min.y) + ((-pixY_chOffset * gp.DigitalPlotItemCnt) - pixY_Offset); pMax.x = gp.PixelRange.Min.x + mx * (itemData2.x - gp.CurrentPlot->XAxis.Min); - pMax.y = ((int) itemData1.y == 0) ? y0 : y1; + int pixY_Offset = 20;//20 pixel from bottom due to mouse cursor label + pMin.y = (gp.PixelRange.Min.y) + ((-gp.DigitalPlotOffset) - pixY_Offset); + pMax.y = (gp.PixelRange.Min.y) + ((-gp.DigitalPlotOffset) - pixY_0 - pixY_1 - pixY_Offset); //plot only one rectangle for same digital state - while (((s+2) < segments) && ((int) itemData1.y == (int) itemData2.y)) { + while (((s+2) < segments) && (itemData1.y == itemData2.y)) { const int i2 = (i1 + 1) % count; itemData2 = getter(i2); pMax.x = gp.PixelRange.Min.x + mx * (itemData2.x - gp.CurrentPlot->XAxis.Min); @@ -2280,6 +2283,7 @@ inline void PlotDigitalEx(const char* label_id, Getter getter, int count, int of } } gp.DigitalPlotItemCnt++; + gp.DigitalPlotOffset += pixYMax; } ImGui::PopClipRect(); diff --git a/implot.h b/implot.h index 6eb67c9..b6e41b4 100644 --- a/implot.h +++ b/implot.h @@ -88,7 +88,8 @@ enum ImPlotStyleVar_ { ImPlotStyleVar_MarkerWeight, // float, outline weight of markers in pixels ImPlotStyleVar_ErrorBarSize, // float, error bar whisker width in pixels ImPlotStyleVar_ErrorBarWeight, // float, error bar whisker weight in pixels - ImPlotStyleVar_DigitalBitHeight, // int, digital channels bit height (at 1) + ImPlotStyleVar_DigitalBitHeight, // float, digital channels bit height (at 1) in pixels + ImPlotStyleVar_DigitalBitGap, // float, digital channels bit padding gap in pixels ImPlotStyleVar_COUNT }; @@ -122,7 +123,8 @@ struct ImPlotStyle { float MarkerWeight; // = 1, outline weight of markers in pixels float ErrorBarSize; // = 5, error bar whisker width in pixels float ErrorBarWeight; // = 1.5, error bar whisker weight in pixels - int DigitalBitHeight; // = 7, digital channels bit height (at 1) + float DigitalBitHeight; // = 8, digital channels bit height (at y = 1.0f) in pixels + float DigitalBitGap; // = 4, digital channels bit padding gap in pixels ImVec4 Colors[ImPlotCol_COUNT]; // array of plot specific colors ImPlotStyle(); }; @@ -176,7 +178,7 @@ void PlotPieChart(const char** label_ids, float* values, int count, const ImVec2 // Plots a text label at point x,y. void PlotLabel(const char* text, float x, float y, bool vertical = false, const ImVec2& pixel_offset = ImVec2(0,0)); // Plots digital channels. -void PlotDigital(const char* label_id, const float* xs, const float* ys, int count, int offset = 0, int stride = sizeof(float) + sizeof(bool)); +void PlotDigital(const char* label_id, const float* xs, const float* ys, int count, int offset = 0, int stride = sizeof(float)); void PlotDigital(const char* label_id, ImVec2 (*getter)(void* data, int idx), void* data, int count, int offset = 0); //----------------------------------------------------------------------------- diff --git a/implot_demo.cpp b/implot_demo.cpp index 2b91691..6b540ac 100644 --- a/implot_demo.cpp +++ b/implot_demo.cpp @@ -48,7 +48,7 @@ struct ScrollingData { } void Erase() { if (Data.size() > 0) { - Data.clear(); + Data.shrink(0); Offset = 0; } } @@ -520,22 +520,22 @@ void ShowImPlotDemoWindow(bool* p_open) { } } - if (ImGui::CollapsingHeader("Digital")) { + if (ImGui::CollapsingHeader("Digital and Analog Signals")) { + - static int bitHeight = 7; - ImGui::SetNextItemWidth(100); - ImGui::DragInt("Bit Hieght", &bitHeight, 0.2, 5, 50); - /// Set the X axis range of the next plot. Call right before BeginPlot(). If ImGuiCond_Always is used, the axis will be locked. - //void SetNextPlotRangeX(float x_min, float x_max, ImGuiCond cond = ImGuiCond_Once); static bool paused = false; - #define K_PLOT_DIGITAL_CH_COUNT 8 - #define K_PLOT_ANALOG_CH_COUNT 8 + #define K_PLOT_DIGITAL_CH_COUNT 4 + #define K_PLOT_ANALOG_CH_COUNT 4 static ScrollingData dataDigital[K_PLOT_DIGITAL_CH_COUNT]; static ScrollingData dataAnalog[K_PLOT_ANALOG_CH_COUNT]; static bool showDigital[K_PLOT_DIGITAL_CH_COUNT]; static bool showAnalog[K_PLOT_ANALOG_CH_COUNT]; - ImGui::BulletText("Drag data items from the left column onto the plot."); + ImGui::BulletText("You can plot digital and analog signals on the same plot."); + ImGui::BulletText("Digital signals do not respond to Y drag and zoom, so that"); + ImGui::Indent(); + ImGui::Text("you can drag analog signals over the rising/falling digital edge."); + ImGui::Unindent(); ImGui::BeginGroup(); if (ImGui::Button("Clear", {100, 0})) { for (int i = 0; i < K_PLOT_DIGITAL_CH_COUNT; ++i) @@ -545,10 +545,16 @@ void ShowImPlotDemoWindow(bool* p_open) { } if (ImGui::Button(paused ? "Resume" : "Pause", {100,0})) paused = !paused; + ImGui::SetNextItemWidth(100); + static float bitHeight = 8; + ImGui::DragFloat("##Bit Height", &bitHeight, 1, 5, 25, "%.0f px"); + ImGui::SetNextItemWidth(100); + static float bitGap = 4; + ImGui::DragFloat("##Bit Gap", &bitGap, 1, 2, 20, "%.0f px"); ImGui::Separator(); for (int i = 0; i < K_PLOT_DIGITAL_CH_COUNT; ++i) { char label[32]; - sprintf(label, "digital_data_%d", i); + sprintf(label, "digital_%d", i); ImGui::Checkbox(label, &showDigital[i]); if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_None)) { ImGui::SetDragDropPayload("DND_DIGITAL_PLOT", &i, sizeof(int)); @@ -558,7 +564,7 @@ void ShowImPlotDemoWindow(bool* p_open) { } for (int i = 0; i < K_PLOT_ANALOG_CH_COUNT; ++i) { char label[32]; - sprintf(label, "analog_data_%d", i); + sprintf(label, "analog_%d", i); ImGui::Checkbox(label, &showAnalog[i]); if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_None)) { ImGui::SetDragDropPayload("DND_ANALOG_PLOT", &i, sizeof(int)); @@ -569,78 +575,52 @@ void ShowImPlotDemoWindow(bool* p_open) { ImGui::EndGroup(); ImGui::SameLine(); static float t = 0; - if (true) { + if (!paused) { t += ImGui::GetIO().DeltaTime; - //digital signal values int i = 0; if (showDigital[i]) - dataDigital[i].AddPoint(t, sin(t) > 0.45); + dataDigital[i].AddPoint(t, sin(2*t) > 0.45); i++; if (showDigital[i]) - dataDigital[i].AddPoint(t, sin(t) < 0.45); + dataDigital[i].AddPoint(t, sin(2*t) < 0.45); i++; if (showDigital[i]) - dataDigital[i].AddPoint(t, sin(t) > 0.83); + dataDigital[i].AddPoint(t, (int)t % 5); i++; if (showDigital[i]) - dataDigital[i].AddPoint(t, sin(t) < 0.17); - i++; - if (showDigital[i]) - dataDigital[i].AddPoint(t, cos(t) > 0.45); - i++; - if (showDigital[i]) - dataDigital[i].AddPoint(t, cos(t) < 0.45); - i++; - if (showDigital[i]) - dataDigital[i].AddPoint(t, cos(t) > 0.83); - i++; - if (showDigital[i]) - dataDigital[i].AddPoint(t, cos(t) < 0.17); - + dataDigital[i].AddPoint(t, sin(2*t) < 0.17); //Analog signal values i = 0; if (showAnalog[i]) - dataAnalog[i].AddPoint(t, sin(t)); + dataAnalog[i].AddPoint(t, sin(2*t)); i++; if (showAnalog[i]) - dataAnalog[i].AddPoint(t, cos(t)); + dataAnalog[i].AddPoint(t, cos(2*t)); i++; if (showAnalog[i]) - dataAnalog[i].AddPoint(t, sin(t) * cos(t)); + dataAnalog[i].AddPoint(t, sin(2*t) * cos(2*t)); i++; if (showAnalog[i]) - dataAnalog[i].AddPoint(t, sin(t) - cos(t)); - i++; - if (showAnalog[i]) - dataAnalog[i].AddPoint(t, cos(t) - sin(t)); - i++; - if (showAnalog[i]) - dataAnalog[i].AddPoint(t, sin(t) + cos(t)); - i++; - if (showAnalog[i]) - dataAnalog[i].AddPoint(t, (sin(t) + cos(t)) / (sin(t) * cos(t))); - i++; - if (showAnalog[i]) - dataAnalog[i].AddPoint(t, (cos(t) + cos(t)) / (cos(t) * cos(t))); - i++; - + dataAnalog[i].AddPoint(t, sin(2*t) - cos(2*t)); } - ImGui::SetNextPlotRangeX(t - 60.0f, t, paused ? ImGuiCond_Once : ImGuiCond_Always); - if (ImGui::BeginPlot("##DND", NULL, NULL, ImVec2(-1,300), ImPlotFlags_Default)) { + ImGui::SetNextPlotRangeY(-1, 1); + ImGui::SetNextPlotRangeX(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]) { char label[32]; - sprintf(label, "digital_data_%d", i); + sprintf(label, "digital_%d", i); ImGui::PushPlotStyleVar(ImPlotStyleVar_DigitalBitHeight, bitHeight); + ImGui::PushPlotStyleVar(ImPlotStyleVar_DigitalBitGap, bitGap); ImGui::PlotDigital(label, &dataDigital[i].Data[0].x, &dataDigital[i].Data[0].y, dataDigital[i].Data.size(), dataDigital[i].Offset, 2 * sizeof(float)); - ImGui::PopPlotStyleVar(); + ImGui::PopPlotStyleVar(2); } } for (int i = 0; i < K_PLOT_ANALOG_CH_COUNT; ++i) { if (showAnalog[i]) { char label[32]; - sprintf(label, "analog_data_%d", i); + sprintf(label, "analog_%d", i); if (dataAnalog[i].Data.size() > 0) ImGui::Plot(label, &dataAnalog[i].Data[0].x, &dataAnalog[i].Data[0].y, dataAnalog[i].Data.size(), dataAnalog[i].Offset, 2 * sizeof(float)); } From 036b4acaab875b0c8fbbca177b3e7c8ee5f21aa8 Mon Sep 17 00:00:00 2001 From: ozlb Date: Mon, 11 May 2020 13:12:22 +0200 Subject: [PATCH 02/11] PlotDigital updates on ImPlot v0.2 --- implot.cpp | 1292 +++++++++++++++++++++++++++++++++++----------------- 1 file changed, 862 insertions(+), 430 deletions(-) diff --git a/implot.cpp b/implot.cpp index 0a89831..b457616 100644 --- a/implot.cpp +++ b/implot.cpp @@ -20,14 +20,38 @@ // 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 +#endif #ifndef IMGUI_DEFINE_MATH_OPERATORS #define IMGUI_DEFINE_MATH_OPERATORS #endif -#include -#include + +#include "implot.h" +#include "imgui_internal.h" #define IM_NORMALIZE2F_OVER_ZERO(VX, VY) \ { \ @@ -41,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; @@ -50,7 +76,6 @@ ImPlotStyle::ImPlotStyle() { ErrorBarSize = 5; ErrorBarWeight = 1.5; DigitalBitHeight = 8; - DigitalBitGap = 4; Colors[ImPlotCol_Line] = IM_COL_AUTO; Colors[ImPlotCol_Fill] = IM_COL_AUTO; @@ -62,16 +87,27 @@ ImPlotStyle::ImPlotStyle() { Colors[ImPlotCol_PlotBorder] = IM_COL_AUTO; Colors[ImPlotCol_XAxis] = IM_COL_AUTO; Colors[ImPlotCol_YAxis] = 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); + Colors[ImPlotCol_QueryX] = ImVec4(1,0,0,1); } -ImPlotRange::ImPlotRange() { - XMin = XMax = YMin = YMax = NAN; +ImPlotRange::ImPlotRange() : Min(NAN), Max(NAN) {} + +bool ImPlotRange::Contains(float v) const { + return v >= Min && v <= Max; } -bool ImPlotRange::Contains(const ImVec2& p) { - return p.x >= XMin && p.x <= XMax && p.y >= YMin && p.y <= YMax; +float ImPlotRange::Size() const { + return Max - Min; +} + +ImPlotLimits::ImPlotLimits() {} + +bool ImPlotLimits::Contains(const ImVec2& p) const { + return X.Contains(p.x) && Y.Contains(p.y); } namespace ImGui { @@ -101,7 +137,7 @@ inline float Remap(float x, float x0, float x1, float y0, float y1) { /// Turns NANs to 0s inline float ConstrainNan(float val) { - return val == NAN || val == -NAN ? 0 : val; + return isnan(val) ? 0 : val; } /// Turns INFINITYs to FLT_MAXs @@ -116,7 +152,7 @@ inline float ConstrainLog(float val) { /// Returns true if val is NAN or INFINITY inline bool NanOrInf(float val) { - return val == INFINITY || val == NAN || val == -INFINITY || val == -NAN; + return val == INFINITY || val == -INFINITY || isnan(val); } /// Utility function to that rounds x to powers of 2,5 and 10 for generating axis labels @@ -223,19 +259,17 @@ struct ImPlotItem { struct ImPlotAxis { ImPlotAxis() { Dragging = false; - Min = 0; - Max = 1; + Range.Min = 0; + Range.Max = 1; Divisions = 3; Subdivisions = 10; - Flags = ImAxisFlags_Default; + Flags = PreviousFlags = ImAxisFlags_Default; } - float Range() { return Max - Min; } bool Dragging; - float Min; - float Max; + ImPlotRange Range; int Divisions; int Subdivisions; - ImAxisFlags Flags; + ImAxisFlags Flags, PreviousFlags; }; /// Holds Plot state information that must persist between frames @@ -243,8 +277,10 @@ struct ImPlot { ImPlot() { Selecting = Querying = Queried = DraggingQuery = false; SelectStart = QueryStart = ImVec2(0,0); - Flags = ImPlotFlags_Default; + Flags = PreviousFlags = ImPlotFlags_Default; + DraggingQueryX[0] = DraggingQueryX[1] = false; ColorIdx = 0; + CurrentYAxis = 0; } ImPool Items; @@ -256,33 +292,35 @@ struct ImPlot { ImVec2 QueryStart; ImRect QueryRect; // relative to BB_grid!! bool DraggingQuery; - ImPlotRange QueryRange; + + bool DraggingQueryX[2]; + ImRect QueryRectX[2]; // relative to BB_grid!! + ImPlotLimits QueryRangeX; ImPlotAxis XAxis; - ImPlotAxis YAxis; - inline ImPlotAxis& Axis(int idx) { return (&XAxis)[idx]; } + ImPlotAxis YAxis[MAX_Y_AXES]; - ImPlotFlags Flags; + + ImPlotFlags Flags, PreviousFlags; int ColorIdx; + int CurrentYAxis; }; struct ImNextPlotData { - ImNextPlotData() { - HasXRange = false; - HasYRange = false; - } + ImNextPlotData() : HasXRange{}, HasYRange{} {} ImGuiCond XRangeCond; - ImGuiCond YRangeCond; + ImGuiCond YRangeCond[MAX_Y_AXES]; bool HasXRange; - bool HasYRange; - float XMin, XMax, YMin, YMax; + bool HasYRange[MAX_Y_AXES]; + ImPlotRange X; + ImPlotRange Y[MAX_Y_AXES]; }; /// Holds Plot state information that must persist only between calls to BeginPlot()/EndPlot() struct ImPlotContext { - ImPlotContext() { + ImPlotContext() : RenderX(), RenderY() { CurrentPlot = NULL; - FitThisFrame = FitX = FitY = false; + FitThisFrame = FitX = false; RestorePlotPalette(); } @@ -305,24 +343,37 @@ struct ImPlotContext { Col_Txt, Col_TxtDis, Col_SlctBg, Col_SlctBd, Col_QryBg, Col_QryBd, - Col_XMajor, Col_XMinor, Col_XTxt, - Col_YMajor, Col_YMinor, Col_YTxt; - // Tick marks - ImVector XTicks, YTicks; - ImGuiTextBuffer XTickLabels, YTickLabels; + Col_QryX; + struct AxisColor { + AxisColor() : Major(), Minor(), Txt() {} + ImU32 Major, Minor, Txt; + }; + AxisColor Col_X; + AxisColor Col_Y[MAX_Y_AXES]; + // Tick marks + ImVector XTicks, YTicks[MAX_Y_AXES]; + ImGuiTextBuffer XTickLabels, YTickLabels[MAX_Y_AXES]; + float AxisLabelReference[MAX_Y_AXES]; // Transformation cache - ImRect PixelRange; - ImVec2 M; // linear scale (slope) - ImVec2 LogDen; // log scale denominator + ImRect PixelRange[MAX_Y_AXES]; + // linear scale (slope) + float Mx; + float My[MAX_Y_AXES]; + // log scale denominator + float LogDenX; + float LogDenY[MAX_Y_AXES]; // Data extents - ImRect Extents; - bool FitThisFrame; bool FitX; bool FitY; + ImPlotRange ExtentsX; + ImPlotRange ExtentsY[MAX_Y_AXES]; + + bool FitThisFrame; bool FitX; + bool FitY[MAX_Y_AXES] = {}; int VisibleItemCount; // Render flags - bool RenderX, RenderY; + bool RenderX, RenderY[MAX_Y_AXES]; // Mouse pos - ImVec2 LastMousePos; + ImVec2 LastMousePos[MAX_Y_AXES]; // Style ImVector ColorMap; ImPlotStyle Style; @@ -343,19 +394,21 @@ static ImPlotContext gp; /// Returns the next unused default plot color ImVec4 NextColor() { - auto col = gp.ColorMap[gp.CurrentPlot->ColorIdx % gp.ColorMap.size()]; + ImVec4 col = gp.ColorMap[gp.CurrentPlot->ColorIdx % gp.ColorMap.size()]; gp.CurrentPlot->ColorIdx++; return col; } inline void FitPoint(const ImVec2& p) { + ImPlotRange* extents_x = &gp.ExtentsX; + ImPlotRange* extents_y = &gp.ExtentsY[gp.CurrentPlot->CurrentYAxis]; if (!NanOrInf(p.x)) { - gp.Extents.Min.x = p.x < gp.Extents.Min.x ? p.x : gp.Extents.Min.x; - gp.Extents.Max.x = p.x > gp.Extents.Max.x ? p.x : gp.Extents.Max.x; + extents_x->Min = p.x < extents_x->Min ? p.x : extents_x->Min; + extents_x->Max = p.x > extents_x->Max ? p.x : extents_x->Max; } if (!NanOrInf(p.y)) { - gp.Extents.Min.y = p.y < gp.Extents.Min.y ? p.y : gp.Extents.Min.y; - gp.Extents.Max.y = p.y > gp.Extents.Max.y ? p.y : gp.Extents.Max.y; + extents_y->Min = p.y < extents_y->Min ? p.y : extents_y->Min; + extents_y->Max = p.y > extents_y->Max ? p.y : extents_y->Max; } } @@ -365,112 +418,118 @@ inline void FitPoint(const ImVec2& p) { inline void UpdateTransformCache() { // get pixels for transforms - gp.PixelRange = ImRect(HasFlag(gp.CurrentPlot->XAxis.Flags, ImAxisFlags_Invert) ? gp.BB_Grid.Max.x : gp.BB_Grid.Min.x, - HasFlag(gp.CurrentPlot->YAxis.Flags, ImAxisFlags_Invert) ? gp.BB_Grid.Min.y : gp.BB_Grid.Max.y, - HasFlag(gp.CurrentPlot->XAxis.Flags, ImAxisFlags_Invert) ? gp.BB_Grid.Min.x : gp.BB_Grid.Max.x, - HasFlag(gp.CurrentPlot->YAxis.Flags, ImAxisFlags_Invert) ? gp.BB_Grid.Max.y : gp.BB_Grid.Min.y); - gp.M.x = (gp.PixelRange.Max.x - gp.PixelRange.Min.x) / (gp.CurrentPlot->XAxis.Max - gp.CurrentPlot->XAxis.Min); - gp.M.y = (gp.PixelRange.Max.y - gp.PixelRange.Min.y) / (gp.CurrentPlot->YAxis.Max - gp.CurrentPlot->YAxis.Min); - gp.LogDen.x = log10(gp.CurrentPlot->XAxis.Max / gp.CurrentPlot->XAxis.Min); - gp.LogDen.y = log10(gp.CurrentPlot->YAxis.Max / gp.CurrentPlot->YAxis.Min); + for (int i = 0; i < MAX_Y_AXES; i++) { + gp.PixelRange[i] = ImRect(HasFlag(gp.CurrentPlot->XAxis.Flags, ImAxisFlags_Invert) ? gp.BB_Grid.Max.x : gp.BB_Grid.Min.x, + HasFlag(gp.CurrentPlot->YAxis[i].Flags, ImAxisFlags_Invert) ? gp.BB_Grid.Min.y : gp.BB_Grid.Max.y, + HasFlag(gp.CurrentPlot->XAxis.Flags, ImAxisFlags_Invert) ? gp.BB_Grid.Min.x : gp.BB_Grid.Max.x, + HasFlag(gp.CurrentPlot->YAxis[i].Flags, ImAxisFlags_Invert) ? gp.BB_Grid.Max.y : gp.BB_Grid.Min.y); + + gp.My[i] = (gp.PixelRange[i].Max.y - gp.PixelRange[i].Min.y) / gp.CurrentPlot->YAxis[i].Range.Size(); + } + gp.LogDenX = log10(gp.CurrentPlot->XAxis.Range.Max / gp.CurrentPlot->XAxis.Range.Min); + for (int i = 0; i < MAX_Y_AXES; i++) { + gp.LogDenY[i] = log10(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(); } -inline ImVec2 PixelsToPlot(float x, float y) { +inline ImVec2 PixelsToPlot(float x, float y, int y_axis_in = -1) { IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "PixelsToPlot() Needs to be called between BeginPlot() and EndPlot()!"); + const int y_axis = y_axis_in >= 0 ? y_axis_in : gp.CurrentPlot->CurrentYAxis; ImVec2 plt; - plt.x = (x - gp.PixelRange.Min.x) / gp.M.x + gp.CurrentPlot->XAxis.Min; - plt.y = (y - gp.PixelRange.Min.y) / gp.M.y + gp.CurrentPlot->YAxis.Min; + plt.x = (x - gp.PixelRange[y_axis].Min.x) / gp.Mx + gp.CurrentPlot->XAxis.Range.Min; + plt.y = (y - gp.PixelRange[y_axis].Min.y) / gp.My[y_axis] + gp.CurrentPlot->YAxis[y_axis].Range.Min; if (HasFlag(gp.CurrentPlot->XAxis.Flags, ImAxisFlags_LogScale)) { - float t = (plt.x - gp.CurrentPlot->XAxis.Min) / (gp.CurrentPlot->XAxis.Max - gp.CurrentPlot->XAxis.Min); - plt.x = pow(10.0f, t * gp.LogDen.x) * gp.CurrentPlot->XAxis.Min; + float t = (plt.x - gp.CurrentPlot->XAxis.Range.Min) / gp.CurrentPlot->XAxis.Range.Size(); + plt.x = pow(10.0f, t * gp.LogDenX) * gp.CurrentPlot->XAxis.Range.Min; } - if (HasFlag(gp.CurrentPlot->YAxis.Flags, ImAxisFlags_LogScale)) { - float t = (plt.y - gp.CurrentPlot->YAxis.Min) / (gp.CurrentPlot->YAxis.Max - gp.CurrentPlot->YAxis.Min); - plt.y = pow(10.0f, t * gp.LogDen.y) * gp.CurrentPlot->YAxis.Min; + if (HasFlag(gp.CurrentPlot->YAxis[y_axis].Flags, ImAxisFlags_LogScale)) { + float t = (plt.y - gp.CurrentPlot->YAxis[y_axis].Range.Min) / gp.CurrentPlot->YAxis[y_axis].Range.Size(); + plt.y = pow(10.0f, t * gp.LogDenY[y_axis]) * gp.CurrentPlot->YAxis[y_axis].Range.Min; } return plt; } -inline ImVec2 PlotToPixels(float x, float y) { +inline ImVec2 PlotToPixels(float x, float y, int y_axis_in = -1) { IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "PlotToPixels() Needs to be called between BeginPlot() and EndPlot()!"); + const int y_axis = y_axis_in >= 0 ? y_axis_in : gp.CurrentPlot->CurrentYAxis; ImVec2 pix; if (HasFlag(gp.CurrentPlot->XAxis.Flags, ImAxisFlags_LogScale)) { - float t = log10(x / gp.CurrentPlot->XAxis.Min) / gp.LogDen.x; - x = ImLerp(gp.CurrentPlot->XAxis.Min, gp.CurrentPlot->XAxis.Max, t); + float t = log10(x / gp.CurrentPlot->XAxis.Range.Min) / gp.LogDenX; + x = ImLerp(gp.CurrentPlot->XAxis.Range.Min, gp.CurrentPlot->XAxis.Range.Max, t); } - if (HasFlag(gp.CurrentPlot->YAxis.Flags, ImAxisFlags_LogScale)) { - float t = log10(y / gp.CurrentPlot->YAxis.Min) / gp.LogDen.y; - y = ImLerp(gp.CurrentPlot->YAxis.Min, gp.CurrentPlot->YAxis.Max, t); + if (HasFlag(gp.CurrentPlot->YAxis[y_axis].Flags, ImAxisFlags_LogScale)) { + float t = log10(y / gp.CurrentPlot->YAxis[y_axis].Range.Min) / gp.LogDenY[y_axis]; + y = ImLerp(gp.CurrentPlot->YAxis[y_axis].Range.Min, gp.CurrentPlot->YAxis[y_axis].Range.Max, t); } - pix.x = gp.PixelRange.Min.x + gp.M.x * (x - gp.CurrentPlot->XAxis.Min); - pix.y = gp.PixelRange.Min.y + gp.M.y * (y - gp.CurrentPlot->YAxis.Min); + pix.x = gp.PixelRange[y_axis].Min.x + gp.Mx * (x - gp.CurrentPlot->XAxis.Range.Min); + pix.y = gp.PixelRange[y_axis].Min.y + gp.My[y_axis] * (y - gp.CurrentPlot->YAxis[y_axis].Range.Min); return pix; } -ImVec2 PixelsToPlot(const ImVec2& pix) { - return PixelsToPlot(pix.x, pix.y); +ImVec2 PixelsToPlot(const ImVec2& pix, int y_axis) { + return PixelsToPlot(pix.x, pix.y, y_axis); } -ImVec2 PlotToPixels(const ImVec2& plt) { - return PlotToPixels(plt.x, plt.y); +ImVec2 PlotToPixels(const ImVec2& plt, int y_axis) { + return PlotToPixels(plt.x, plt.y, y_axis); } struct Plt2PixLinLin { - static inline ImVec2 Transform(const ImVec2& plt) { return Transform(plt.x, plt.y); } - static inline ImVec2 Transform(float x, float y) { - return { gp.PixelRange.Min.x + gp.M.x * (x - gp.CurrentPlot->XAxis.Min), - gp.PixelRange.Min.y + gp.M.y * (y - gp.CurrentPlot->YAxis.Min) }; - } -}; + Plt2PixLinLin(int y_axis_in) : y_axis(y_axis_in) {} -struct Plt2PixLinLinObj { - Plt2PixLinLinObj() { - a = gp.PixelRange.Min.x; - b = gp.M.x; - c = gp.CurrentPlot->XAxis.Min; - d = gp.PixelRange.Min.y; - e = gp.M.y; - f = gp.CurrentPlot->YAxis.Min; + ImVec2 operator()(const ImVec2& plt) { return (*this)(plt.x, plt.y); } + ImVec2 operator()(float x, float y) { + return { gp.PixelRange[y_axis].Min.x + gp.Mx * (x - gp.CurrentPlot->XAxis.Range.Min), + gp.PixelRange[y_axis].Min.y + gp.My[y_axis] * (y - gp.CurrentPlot->YAxis[y_axis].Range.Min) }; } - inline ImVec2 Transform(const ImVec2& plt) { return Transform(plt.x, plt.y); } - inline ImVec2 Transform(float x, float y) { - return { a + b * (x - c), d + e * (y - f) }; - } - float a, b, c, d, e, f; -}; + int y_axis; +}; struct Plt2PixLogLin { - static inline ImVec2 Transform(const ImVec2& plt) { return Transform(plt.x, plt.y); } - static inline ImVec2 Transform(float x, float y) { - float t = log10(x / gp.CurrentPlot->XAxis.Min) / gp.LogDen.x; - x = ImLerp(gp.CurrentPlot->XAxis.Min, gp.CurrentPlot->XAxis.Max, t); - return { gp.PixelRange.Min.x + gp.M.x * (x - gp.CurrentPlot->XAxis.Min), - gp.PixelRange.Min.y + gp.M.y * (y - gp.CurrentPlot->YAxis.Min) }; + Plt2PixLogLin(int y_axis_in) : y_axis(y_axis_in) {} + + ImVec2 operator()(const ImVec2& plt) { return (*this)(plt.x, plt.y); } + ImVec2 operator()(float x, float y) { + float t = log10(x / gp.CurrentPlot->XAxis.Range.Min) / gp.LogDenX; + x = ImLerp(gp.CurrentPlot->XAxis.Range.Min, gp.CurrentPlot->XAxis.Range.Max, t); + return { gp.PixelRange[y_axis].Min.x + gp.Mx * (x - gp.CurrentPlot->XAxis.Range.Min), + gp.PixelRange[y_axis].Min.y + gp.My[y_axis] * (y - gp.CurrentPlot->YAxis[y_axis].Range.Min) }; } + + int y_axis; }; struct Plt2PixLinLog { - static inline ImVec2 Transform(const ImVec2& plt) { return Transform(plt.x, plt.y); } - static inline ImVec2 Transform(float x, float y) { - float t = log10(y / gp.CurrentPlot->YAxis.Min) / gp.LogDen.y; - y = ImLerp(gp.CurrentPlot->YAxis.Min, gp.CurrentPlot->YAxis.Max, t); - return { gp.PixelRange.Min.x + gp.M.x * (x - gp.CurrentPlot->XAxis.Min), - gp.PixelRange.Min.y + gp.M.y * (y - gp.CurrentPlot->YAxis.Min) }; + Plt2PixLinLog(int y_axis_in) : y_axis(y_axis_in) {} + + ImVec2 operator()(const ImVec2& plt) { return (*this)(plt.x, plt.y); } + ImVec2 operator()(float x, float y) { + float t = log10(y / gp.CurrentPlot->YAxis[y_axis].Range.Min) / gp.LogDenY[y_axis]; + y = ImLerp(gp.CurrentPlot->YAxis[y_axis].Range.Min, gp.CurrentPlot->YAxis[y_axis].Range.Max, t); + return { gp.PixelRange[y_axis].Min.x + gp.Mx * (x - gp.CurrentPlot->XAxis.Range.Min), + gp.PixelRange[y_axis].Min.y + gp.My[y_axis] * (y - gp.CurrentPlot->YAxis[y_axis].Range.Min) }; } + + int y_axis; }; struct Plt2PixLogLog { - static inline ImVec2 Transform(const ImVec2& plt) { return Transform(plt.x, plt.y); } - static inline ImVec2 Transform(float x, float y) { - float t = log10(x / gp.CurrentPlot->XAxis.Min) / gp.LogDen.x; - x = ImLerp(gp.CurrentPlot->XAxis.Min, gp.CurrentPlot->XAxis.Max, t); - t = log10(y / gp.CurrentPlot->YAxis.Min) / gp.LogDen.y; - y = ImLerp(gp.CurrentPlot->YAxis.Min, gp.CurrentPlot->YAxis.Max, t); - return { gp.PixelRange.Min.x + gp.M.x * (x - gp.CurrentPlot->XAxis.Min), - gp.PixelRange.Min.y + gp.M.y * (y - gp.CurrentPlot->YAxis.Min) }; + Plt2PixLogLog(int y_axis_in) : y_axis(y_axis_in) {} + + ImVec2 operator()(const ImVec2& plt) { return (*this)(plt.x, plt.y); } + ImVec2 operator()(float x, float y) { + float t = log10(x / gp.CurrentPlot->XAxis.Range.Min) / gp.LogDenX; + x = ImLerp(gp.CurrentPlot->XAxis.Range.Min, gp.CurrentPlot->XAxis.Range.Max, t); + t = log10(y / gp.CurrentPlot->YAxis[y_axis].Range.Min) / gp.LogDenY[y_axis]; + y = ImLerp(gp.CurrentPlot->YAxis[y_axis].Range.Min, gp.CurrentPlot->YAxis[y_axis].Range.Max, t); + return { gp.PixelRange[y_axis].Min.x + gp.Mx * (x - gp.CurrentPlot->XAxis.Range.Min), + gp.PixelRange[y_axis].Min.y + gp.My[y_axis] * (y - gp.CurrentPlot->YAxis[y_axis].Range.Min) }; } + + int y_axis; }; //----------------------------------------------------------------------------- @@ -508,37 +567,37 @@ const char* GetLegendLabel(int i) { // Tick Utils //----------------------------------------------------------------------------- -inline void GetTicks(float tMin, float tMax, int nMajor, int nMinor, bool logscale, ImVector &out) { +inline void GetTicks(const ImPlotRange& scale, int nMajor, int nMinor, bool logscale, ImVector &out) { out.shrink(0); if (logscale) { - if (tMin <= 0 || tMax <= 0) + if (scale.Min <= 0 || scale.Max <= 0) return; - int exp_min = (int)(ImFloor(log10(tMin))); - int exp_max = (int)(ImCeil(log10(tMax))); + int exp_min = (int)(ImFloor(log10(scale.Min))); + int exp_max = (int)(ImCeil(log10(scale.Max))); for (int e = exp_min - 1; e < exp_max + 1; ++e) { double major1 = ImPow(10, (double)(e)); double major2 = ImPow(10, (double)(e + 1)); double interval = (major2 - major1) / 9; - if (major1 >= (tMin - FLT_EPSILON) && major1 <= (tMax + FLT_EPSILON)) + if (major1 >= (scale.Min - FLT_EPSILON) && major1 <= (scale.Max + FLT_EPSILON)) out.push_back(ImTick(major1, true)); for (int i = 1; i < 9; ++i) { double minor = major1 + i * interval; - if (minor >= (tMin - FLT_EPSILON) && minor <= (tMax + FLT_EPSILON)) + if (minor >= (scale.Min - FLT_EPSILON) && minor <= (scale.Max + FLT_EPSILON)) out.push_back(ImTick(minor, false, false)); } } } else { - const double range = NiceNum(tMax - tMin, 0); + const double range = NiceNum(scale.Max - scale.Min, 0); const double interval = NiceNum(range / (nMajor - 1), 1); - const double graphmin = floor(tMin / interval) * interval; - const double graphmax = ceil(tMax / interval) * interval; + const double graphmin = floor(scale.Min / interval) * interval; + const double graphmax = ceil(scale.Max / interval) * interval; for (double major = graphmin; major < graphmax + 0.5 * interval; major += interval) { - if (major >= tMin && major <= tMax) + if (major >= scale.Min && major <= scale.Max) out.push_back(ImTick(major, true)); for (int i = 1; i < nMinor; ++i) { double minor = major + i * interval / nMinor; - if (minor >= tMin && minor <= tMax) + if (minor >= scale.Min && minor <= scale.Max) out.push_back(ImTick(minor, false)); } } @@ -548,7 +607,7 @@ inline void GetTicks(float tMin, float tMax, int nMajor, int nMinor, bool logsca inline void LabelTicks(ImVector &ticks, bool scientific, ImGuiTextBuffer& buffer) { buffer.Buf.resize(0); char temp[32]; - for (auto &tk : ticks) { + for (ImTick &tk : ticks) { if (tk.RenderLabel) { tk.TextOffset = buffer.size(); if (scientific) @@ -561,11 +620,88 @@ inline void LabelTicks(ImVector &ticks, bool scientific, ImGuiTextBuffer } } +namespace { +struct AxisState { + ImPlotAxis* axis; + bool has_range; + ImGuiCond range_cond; + bool present; + int present_so_far; + bool flip; + bool lock_min; + bool lock_max; + bool lock; + + AxisState(ImPlotAxis& axis_in, bool has_range_in, ImGuiCond range_cond_in, + bool present_in, int previous_present) + : axis(&axis_in), + has_range(has_range_in), + range_cond(range_cond_in), + present(present_in), + present_so_far(previous_present + (present ? 1 : 0)), + flip(HasFlag(axis->Flags, ImAxisFlags_Invert)), + lock_min(HasFlag(axis->Flags, ImAxisFlags_LockMin)), + lock_max(HasFlag(axis->Flags, ImAxisFlags_LockMax)), + lock(present && ((lock_min && lock_max) || (has_range && range_cond == ImGuiCond_Always))) {} + + AxisState() + : axis(), + has_range(), + range_cond(), + present(), + present_so_far(), + flip(), + lock_min(), + lock_max(), + lock() {} +}; + +void UpdateAxisColor(int axis_flag, ImPlotContext::AxisColor* col) { + 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 = GetColorU32(col_Axis); + col->Minor = GetColorU32(col_Axis * ImVec4(1, 1, 1, 0.25f)); + col->Txt = GetColorU32({col_Axis.x, col_Axis.y, col_Axis.z, 1}); +} + +ImRect GetAxisScale(int y_axis, float tx, float ty, float zoom_rate) { + return ImRect( + PixelsToPlot(gp.BB_Grid.Min - gp.BB_Grid.GetSize() * ImVec2(tx * zoom_rate, ty * zoom_rate), y_axis), + PixelsToPlot(gp.BB_Grid.Max + gp.BB_Grid.GetSize() * ImVec2((1 - tx) * zoom_rate, (1 - ty) * zoom_rate), y_axis)); +} + +class YPadCalculator { + public: + 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) { + ImPlot& plot = *gp.CurrentPlot; + 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. + float pad_result = 0; + if (AxisStates[y_axis].present_so_far >= 3) { + pad_result += 6.0f; + } + if (!HasFlag(plot.YAxis[y_axis].Flags, ImAxisFlags_TickLabels)) { + return pad_result; + } + pad_result += MaxLabelWidths[y_axis] + TxtOff; + return pad_result; + } + + private: + const AxisState* const AxisStates; + const float* const MaxLabelWidths; + const float TxtOff; +}; +} // namespace + //----------------------------------------------------------------------------- // BeginPlot() //----------------------------------------------------------------------------- -bool BeginPlot(const char* title, const char* x_label, const char* y_label, const ImVec2& size, ImPlotFlags flags, ImAxisFlags x_flags, ImAxisFlags y_flags) { +bool BeginPlot(const char* title, const char* x_label, const char* y_label, const ImVec2& size, ImPlotFlags flags, ImAxisFlags x_flags, ImAxisFlags y_flags, ImAxisFlags y2_flags, ImAxisFlags y3_flags) { IM_ASSERT_USER_ERROR(gp.CurrentPlot == NULL, "Mismatched BeginPlot()/EndPlot()!"); @@ -586,11 +722,33 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons gp.CurrentPlot = gp.Plots.GetOrAddByKey(ID); ImPlot &plot = *gp.CurrentPlot; + plot.CurrentYAxis = 0; + if (just_created) { - plot.Flags = flags; - plot.XAxis.Flags = x_flags; - plot.YAxis.Flags = y_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)) { @@ -606,53 +764,56 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons if (gp.NextPlotData.HasXRange) { if (just_created || gp.NextPlotData.XRangeCond == ImGuiCond_Always) { - plot.XAxis.Min = gp.NextPlotData.XMin; - plot.XAxis.Max = gp.NextPlotData.XMax; + plot.XAxis.Range = gp.NextPlotData.X; } } - if (gp.NextPlotData.HasYRange) { - if (just_created || gp.NextPlotData.YRangeCond == ImGuiCond_Always) - { - plot.YAxis.Min = gp.NextPlotData.YMin; - plot.YAxis.Max = gp.NextPlotData.YMax; + for (int i = 0; i < MAX_Y_AXES; i++) { + if (gp.NextPlotData.HasYRange[i]) { + if (just_created || gp.NextPlotData.YRangeCond[i] == ImGuiCond_Always) + { + plot.YAxis[i].Range = gp.NextPlotData.Y[i]; + } } } // AXIS STATES ------------------------------------------------------------ + 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.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 flip_x = HasFlag(plot.XAxis.Flags, ImAxisFlags_Invert); - const bool lock_x_min = HasFlag(plot.XAxis.Flags, ImAxisFlags_LockMin); - const bool lock_x_max = HasFlag(plot.XAxis.Flags, ImAxisFlags_LockMax); - const bool lock_x = (lock_x_min && lock_x_max) || (gp.NextPlotData.HasXRange && gp.NextPlotData.XRangeCond == ImGuiCond_Always); + const bool lock_plot = x.lock && y[0].lock && y[1].lock && y[2].lock; - const bool flip_y = HasFlag(plot.YAxis.Flags, ImAxisFlags_Invert); - const bool lock_y_min = HasFlag(plot.YAxis.Flags, ImAxisFlags_LockMin); - const bool lock_y_max = HasFlag(plot.YAxis.Flags, ImAxisFlags_LockMax); - const bool lock_y = (lock_y_min && lock_y_max) || (gp.NextPlotData.HasYRange && gp.NextPlotData.YRangeCond == ImGuiCond_Always); - - const bool lock_plot = lock_x && lock_y; - // CONSTRAINTS ------------------------------------------------------------ - plot.XAxis.Min = ConstrainNan(ConstrainInf(plot.XAxis.Min)); - plot.XAxis.Max = ConstrainNan(ConstrainInf(plot.XAxis.Max)); - plot.YAxis.Min = ConstrainNan(ConstrainInf(plot.YAxis.Min)); - plot.YAxis.Max = ConstrainNan(ConstrainInf(plot.YAxis.Max)); + 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++) { + plot.YAxis[i].Range.Min = ConstrainNan(ConstrainInf(plot.YAxis[i].Range.Min)); + plot.YAxis[i].Range.Max = ConstrainNan(ConstrainInf(plot.YAxis[i].Range.Max)); + } if (HasFlag(plot.XAxis.Flags, ImAxisFlags_LogScale)) - plot.XAxis.Min = ConstrainLog(plot.XAxis.Min); + plot.XAxis.Range.Min = ConstrainLog(plot.XAxis.Range.Min); if (HasFlag(plot.XAxis.Flags, ImAxisFlags_LogScale)) - plot.XAxis.Max = ConstrainLog(plot.XAxis.Max); - if (HasFlag(plot.YAxis.Flags, ImAxisFlags_LogScale)) - plot.YAxis.Min = ConstrainLog(plot.YAxis.Min); - if (HasFlag(plot.YAxis.Flags, ImAxisFlags_LogScale)) - plot.YAxis.Max = ConstrainLog(plot.YAxis.Max); + plot.XAxis.Range.Max = ConstrainLog(plot.XAxis.Range.Max); + for (int i = 0; i < MAX_Y_AXES; i++) { + if (HasFlag(plot.YAxis[i].Flags, ImAxisFlags_LogScale)) + plot.YAxis[i].Range.Min = ConstrainLog(plot.YAxis[i].Range.Min); + if (HasFlag(plot.YAxis[i].Flags, ImAxisFlags_LogScale)) + plot.YAxis[i].Range.Max = ConstrainLog(plot.YAxis[i].Range.Max); + } - if (plot.XAxis.Max <= plot.XAxis.Min) - plot.XAxis.Max = plot.XAxis.Min + FLT_EPSILON; - if (plot.YAxis.Max <= plot.YAxis.Min) - plot.YAxis.Max = plot.YAxis.Min + FLT_EPSILON; + if (plot.XAxis.Range.Max <= plot.XAxis.Range.Min) + plot.XAxis.Range.Max = plot.XAxis.Range.Min + FLT_EPSILON; + for (int i = 0; i < MAX_Y_AXES; i++) { + if (plot.YAxis[i].Range.Max <= plot.YAxis[i].Range.Min) + plot.YAxis[i].Range.Max = plot.YAxis[i].Range.Min + FLT_EPSILON; + } // adaptive divisions if (HasFlag(plot.XAxis.Flags, ImAxisFlags_Adaptive)) { @@ -660,10 +821,12 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons if (plot.XAxis.Divisions < 2) plot.XAxis.Divisions = 2; } - if (HasFlag(plot.YAxis.Flags, ImAxisFlags_Adaptive)) { - plot.YAxis.Divisions = (int)IM_ROUND(0.003 * gp.BB_Canvas.GetHeight()); - if (plot.YAxis.Divisions < 2) - plot.YAxis.Divisions = 2; + for (int i = 0; i < MAX_Y_AXES; i++) { + if (HasFlag(plot.YAxis[i].Flags, ImAxisFlags_Adaptive)) { + plot.YAxis[i].Divisions = (int)IM_ROUND(0.003 * gp.BB_Canvas.GetHeight()); + if (plot.YAxis[i].Divisions < 2) + plot.YAxis[i].Divisions = 2; + } } // COLORS ----------------------------------------------------------------- @@ -672,15 +835,10 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons gp.Col_Bg = gp.Style.Colors[ImPlotCol_PlotBg].w == -1 ? GetColorU32(ImGuiCol_WindowBg) : GetColorU32(gp.Style.Colors[ImPlotCol_PlotBg]); gp.Col_Border = gp.Style.Colors[ImPlotCol_PlotBorder].w == -1 ? GetColorU32(ImGuiCol_Text, 0.5f) : GetColorU32(gp.Style.Colors[ImPlotCol_PlotBorder]); - const ImVec4 col_xAxis = gp.Style.Colors[ImPlotCol_XAxis].w == -1 ? ImGui::GetStyle().Colors[ImGuiCol_Text] * ImVec4(1, 1, 1, 0.25f) : gp.Style.Colors[ImPlotCol_XAxis]; - gp.Col_XMajor = GetColorU32(col_xAxis); - gp.Col_XMinor = GetColorU32(col_xAxis * ImVec4(1, 1, 1, 0.25f)); - gp.Col_XTxt = GetColorU32({col_xAxis.x, col_xAxis.y, col_xAxis.z, 1}); - - const ImVec4 col_yAxis = gp.Style.Colors[ImPlotCol_YAxis].w == -1 ? ImGui::GetStyle().Colors[ImGuiCol_Text] * ImVec4(1, 1, 1, 0.25f) : gp.Style.Colors[ImPlotCol_YAxis]; - gp.Col_YMajor = GetColorU32(col_yAxis); - gp.Col_YMinor = GetColorU32(col_yAxis * ImVec4(1, 1, 1, 0.25f)); - gp.Col_YTxt = GetColorU32({col_yAxis.x, col_yAxis.y, col_yAxis.z, 1}); + UpdateAxisColor(ImPlotCol_XAxis, &gp.Col_X); + UpdateAxisColor(ImPlotCol_YAxis, &gp.Col_Y[0]); + 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); @@ -689,6 +847,8 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons gp.Col_QryBg = GetColorU32(gp.Style.Colors[ImPlotCol_Query] * ImVec4(1,1,1,0.25f)); gp.Col_QryBd = GetColorU32(gp.Style.Colors[ImPlotCol_Query]); + gp.Col_QryX = GetColorU32(gp.Style.Colors[ImPlotCol_QueryX]); + // BB AND HOVER ----------------------------------------------------------- // frame @@ -708,28 +868,38 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons // canvas bb gp.BB_Canvas = ImRect(gp.BB_Frame.Min + Style.WindowPadding, gp.BB_Frame.Max - Style.WindowPadding); - gp.RenderX = (HasFlag(plot.XAxis.Flags, ImAxisFlags_GridLines) || - HasFlag(plot.XAxis.Flags, ImAxisFlags_TickMarks) || + gp.RenderX = (HasFlag(plot.XAxis.Flags, ImAxisFlags_GridLines) || + HasFlag(plot.XAxis.Flags, ImAxisFlags_TickMarks) || HasFlag(plot.XAxis.Flags, ImAxisFlags_TickLabels)) && plot.XAxis.Divisions > 1; - gp.RenderY = (HasFlag(plot.YAxis.Flags, ImAxisFlags_GridLines) || - HasFlag(plot.YAxis.Flags, ImAxisFlags_TickMarks) || - HasFlag(plot.YAxis.Flags, ImAxisFlags_TickLabels)) && plot.YAxis.Divisions > 1; + for (int i = 0; i < MAX_Y_AXES; i++) { + gp.RenderY[i] = + y[i].present && + (HasFlag(plot.YAxis[i].Flags, ImAxisFlags_GridLines) || + HasFlag(plot.YAxis[i].Flags, ImAxisFlags_TickMarks) || + HasFlag(plot.YAxis[i].Flags, ImAxisFlags_TickLabels)) && plot.YAxis[i].Divisions > 1; + } // get ticks if (gp.RenderX) - GetTicks(plot.XAxis.Min, plot.XAxis.Max, plot.XAxis.Divisions, plot.XAxis.Subdivisions, HasFlag(plot.XAxis.Flags, ImAxisFlags_LogScale), gp.XTicks); - if (gp.RenderY) - GetTicks(plot.YAxis.Min, plot.YAxis.Max, plot.YAxis.Divisions, plot.YAxis.Subdivisions, HasFlag(plot.YAxis.Flags, ImAxisFlags_LogScale), gp.YTicks); + GetTicks(plot.XAxis.Range, plot.XAxis.Divisions, plot.XAxis.Subdivisions, HasFlag(plot.XAxis.Flags, ImAxisFlags_LogScale), gp.XTicks); + for (int i = 0; i < MAX_Y_AXES; i++) { + if (gp.RenderY[i]) { + GetTicks(plot.YAxis[i].Range, plot.YAxis[i].Divisions, plot.YAxis[i].Subdivisions, HasFlag(plot.YAxis[i].Flags, ImAxisFlags_LogScale), gp.YTicks[i]); + } + } // label ticks if (HasFlag(plot.XAxis.Flags, ImAxisFlags_TickLabels)) LabelTicks(gp.XTicks, HasFlag(plot.XAxis.Flags, ImAxisFlags_Scientific), gp.XTickLabels); - float max_label_width = 0; - if (HasFlag(plot.YAxis.Flags, ImAxisFlags_TickLabels)) { - LabelTicks(gp.YTicks, HasFlag(plot.YAxis.Flags, ImAxisFlags_Scientific), gp.YTickLabels); - for (auto &yt : gp.YTicks) - max_label_width = yt.Size.x > max_label_width ? yt.Size.x : max_label_width; + float max_label_width[MAX_Y_AXES] = {}; + for (int i = 0; i < MAX_Y_AXES; i++) { + if (y[i].present && HasFlag(plot.YAxis[i].Flags, ImAxisFlags_TickLabels)) { + LabelTicks(gp.YTicks[i], HasFlag(plot.YAxis[i].Flags, ImAxisFlags_Scientific), gp.YTickLabels[i]); + for (ImTick &yt : gp.YTicks[i]) { + max_label_width[i] = yt.Size.x > max_label_width[i] ? yt.Size.x : max_label_width[i]; + } + } } // grid bb @@ -738,34 +908,56 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons const float txt_height = GetTextLineHeight(); const float pad_top = title_size.x > 0.0f ? txt_height + txt_off : 0; const float pad_bot = (HasFlag(plot.XAxis.Flags, ImAxisFlags_TickLabels) ? txt_height + txt_off : 0) + (x_label ? txt_height + txt_off : 0); - const float pad_left = (HasFlag(plot.YAxis.Flags, ImAxisFlags_TickLabels) ? max_label_width + txt_off : 0) + (y_label ? txt_height + txt_off : 0); - gp.BB_Grid = ImRect(gp.BB_Canvas.Min + ImVec2(pad_left, pad_top), gp.BB_Canvas.Max - ImVec2(0, pad_bot)); + YPadCalculator y_axis_pad(y, max_label_width, txt_off); + const float pad_left = y_axis_pad(0) + (y_label ? txt_height + txt_off : 0); + const float pad_right = y_axis_pad(1) + y_axis_pad(2); + gp.BB_Grid = ImRect(gp.BB_Canvas.Min + ImVec2(pad_left, pad_top), gp.BB_Canvas.Max - ImVec2(pad_right, pad_bot)); 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); - const ImRect yAxisRegion_bb({gp.BB_Frame.Min.x, gp.BB_Grid.Min.y}, gp.BB_Grid.Max - ImVec2(0, 10)); - const bool hov_y_axis_region = yAxisRegion_bb.Contains(IO.MousePos); + + // The left labels are referenced to the left of the bounding box. + gp.AxisLabelReference[0] = gp.BB_Grid.Min.x; + // If Y axis 1 is present, its labels will be referenced to the + // right of the bounding box. + gp.AxisLabelReference[1] = gp.BB_Grid.Max.x; + // The third axis may be either referenced to the right of the + // bounding box, or 6 pixels further past the end of the 2nd axis. + gp.AxisLabelReference[2] = + !y[1].present ? + gp.BB_Grid.Max.x : + (gp.AxisLabelReference[1] + y_axis_pad(1) + 6); + + ImRect yAxisRegion_bb[MAX_Y_AXES]; + yAxisRegion_bb[0] = ImRect({gp.BB_Frame.Min.x, gp.BB_Grid.Min.y}, {gp.BB_Grid.Min.x + 6, gp.BB_Grid.Max.y - 10}); + // The auxiliary y axes are off to the right of the BB grid. + yAxisRegion_bb[1] = ImRect({gp.BB_Grid.Max.x - 6, gp.BB_Grid.Min.y}, + gp.BB_Grid.Max + ImVec2(y_axis_pad(1), 0)); + yAxisRegion_bb[2] = ImRect({gp.AxisLabelReference[2] - 6, gp.BB_Grid.Min.y}, + yAxisRegion_bb[1].Max + ImVec2(y_axis_pad(2), 0)); + + ImRect centralRegion({gp.BB_Grid.Min.x + 6, gp.BB_Grid.Min.y}, + {gp.BB_Grid.Max.x - 6, gp.BB_Grid.Max.y}); + + const bool hov_y_axis_region[MAX_Y_AXES] = { + y[0].present && (yAxisRegion_bb[0].Contains(IO.MousePos) || centralRegion.Contains(IO.MousePos)), + 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]; // 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) { - ImRect bb_query; - if (HasFlag(plot.Flags, ImPlotFlags_PixelQuery)) { - bb_query = plot.QueryRect; - bb_query.Min += gp.BB_Grid.Min; - bb_query.Max += gp.BB_Grid.Min; - } - else { - UpdateTransformCache(); - ImVec2 p1 = PlotToPixels(plot.QueryRange.XMin, plot.QueryRange.YMin); - ImVec2 p2 = PlotToPixels(plot.QueryRange.XMax, plot.QueryRange.YMax); - bb_query.Min = ImVec2(ImMin(p1.x,p2.x), ImMin(p1.y,p2.y)); - bb_query.Max = ImVec2(ImMax(p1.x,p2.x), ImMax(p1.y,p2.y)); - } + if (gp.Hov_Frame && gp.Hov_Grid && plot.Queried && !plot.Querying) { + ImRect bb_query = plot.QueryRect; + + bb_query.Min += gp.BB_Grid.Min; + bb_query.Max += gp.BB_Grid.Min; + hov_query = bb_query.Contains(IO.MousePos); } @@ -775,97 +967,169 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons } if (plot.DraggingQuery) { SetMouseCursor(ImGuiMouseCursor_ResizeAll); - if (!HasFlag(plot.Flags, ImPlotFlags_PixelQuery)) { - ImVec2 p1 = PlotToPixels(plot.QueryRange.XMin, plot.QueryRange.YMin); - ImVec2 p2 = PlotToPixels(plot.QueryRange.XMax, plot.QueryRange.YMax); - plot.QueryRect.Min = ImVec2(ImMin(p1.x,p2.x), ImMin(p1.y,p2.y)) + IO.MouseDelta; - plot.QueryRect.Max = ImVec2(ImMax(p1.x,p2.x), ImMax(p1.y,p2.y)) + IO.MouseDelta; - p1 = PixelsToPlot(plot.QueryRect.Min); - p2 = PixelsToPlot(plot.QueryRect.Max); - plot.QueryRect.Min -= gp.BB_Grid.Min; - plot.QueryRect.Max -= gp.BB_Grid.Min; - plot.QueryRange.XMin = ImMin(p1.x, p2.x); - plot.QueryRange.XMax = ImMax(p1.x, p2.x); - plot.QueryRange.YMin = ImMin(p1.y, p2.y); - plot.QueryRange.YMax = ImMax(p1.y, p2.y); - } - else { - plot.QueryRect.Min += IO.MouseDelta; - plot.QueryRect.Max += IO.MouseDelta; - } + 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); - if (IO.MouseDown[0] && !plot.XAxis.Dragging && !plot.YAxis.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; } } + //QUERY X + bool hov_queryX[2]; + for (size_t i = 0; i < 2; i++) + { + hov_queryX[i] = plot.QueryRectX[i].Contains(IO.MousePos); + //x limits + bool xAtMax = false; + if (plot.QueryRectX[i].Min.x <= gp.BB_Grid.Min.x) { + plot.QueryRectX[i].Min.x = gp.BB_Grid.Min.x; + } + if (plot.QueryRectX[i].Max.x >= (gp.BB_Grid.Max.x)) { + plot.QueryRectX[i].Max.x = gp.BB_Grid.Max.x; + xAtMax = true; + } + //min cursor "line" width + if ((plot.QueryRectX[i].Max.x - plot.QueryRectX[i].Min.x) < 3) { + if (xAtMax) + plot.QueryRectX[i].Min.x = plot.QueryRectX[i].Max.x - 3; + else + plot.QueryRectX[i].Max.x = plot.QueryRectX[i].Min.x + 3; + } + //y locked to min max grid + plot.QueryRectX[i].Min.y = gp.BB_Grid.Min.y; + plot.QueryRectX[i].Max.y = gp.BB_Grid.Max.y; + // CURSOR1 DRAG ------------------------------------------------------------- + if (plot.DraggingQueryX[i] && (IO.MouseReleased[0] || !IO.MouseDown[0])) { + plot.DraggingQueryX[i] = false; + } + if (plot.DraggingQueryX[i]) { + ImGui::SetMouseCursor(ImGuiMouseCursor_ResizeEW); + plot.QueryRectX[i].Min += IO.MouseDelta; + plot.QueryRectX[i].Max += IO.MouseDelta; + //x limits + //if (plot.QueryRectX[i].Min.x < gp.BB_Grid.Min.x) plot.QueryRectX[i].Min.x = gp.BB_Grid.Min.x; + //if (plot.QueryRectX[i].Max.x > (gp.BB_Grid.Max.x - 10)) plot.QueryRectX[i].Max.x = gp.BB_Grid.Max.x - 10; + } + if (gp.Hov_Frame && hov_queryX[i] && !plot.DraggingQueryX[i] && !plot.Selecting && !plot.DraggingQuery && !hov_legend) { + ImGui::SetMouseCursor(ImGuiMouseCursor_ResizeEW); + if (IO.MouseDown[0] && !plot.XAxis.Dragging && !(plot.YAxis[0].Dragging || plot.YAxis[1].Dragging || plot.YAxis[2].Dragging)) { + //allow only one cursor dragging per time + if (i==0) + plot.DraggingQueryX[i] = !plot.DraggingQueryX[1]; + else + plot.DraggingQueryX[i] = !plot.DraggingQueryX[0]; + } + } + } + // DRAG INPUT ------------------------------------------------------------- + // end drags if (plot.XAxis.Dragging && (IO.MouseReleased[0] || !IO.MouseDown[0])) { plot.XAxis.Dragging = false; G.IO.MouseDragMaxDistanceSqr[0] = 0; } - if (plot.YAxis.Dragging && (IO.MouseReleased[0] || !IO.MouseDown[0])) { - plot.YAxis.Dragging = false; - G.IO.MouseDragMaxDistanceSqr[0] = 0; + for (int i = 0; i < MAX_Y_AXES; i++) { + if (plot.YAxis[i].Dragging && (IO.MouseReleased[0] || !IO.MouseDown[0])) { + plot.YAxis[i].Dragging = false; + G.IO.MouseDragMaxDistanceSqr[0] = 0; + } } + const bool any_y_dragging = plot.YAxis[0].Dragging || plot.YAxis[1].Dragging || plot.YAxis[2].Dragging; + const bool any_queryX_dragging = plot.DraggingQueryX[0] || plot.DraggingQueryX[1]; + bool drag_in_progress = plot.XAxis.Dragging || any_y_dragging || any_queryX_dragging; // do drag - if (plot.XAxis.Dragging || plot.YAxis.Dragging) { + if (drag_in_progress) { UpdateTransformCache(); - ImVec2 plot_tl = PixelsToPlot(gp.BB_Grid.Min - IO.MouseDelta); - ImVec2 plot_br = PixelsToPlot(gp.BB_Grid.Max - IO.MouseDelta); - if (!lock_x && plot.XAxis.Dragging) { - if (!lock_x_min) - plot.XAxis.Min = flip_x ? plot_br.x : plot_tl.x; - if (!lock_x_max) - plot.XAxis.Max = flip_x ? plot_tl.x : plot_br.x; + if (!x.lock && plot.XAxis.Dragging) { + ImVec2 plot_tl = PixelsToPlot(gp.BB_Grid.Min - IO.MouseDelta, 0); + ImVec2 plot_br = PixelsToPlot(gp.BB_Grid.Max - IO.MouseDelta, 0); + if (!x.lock_min) + plot.XAxis.Range.Min = x.flip ? plot_br.x : plot_tl.x; + if (!x.lock_max) + plot.XAxis.Range.Max = x.flip ? plot_tl.x : plot_br.x; } - if (!lock_y && plot.YAxis.Dragging) { - if (!lock_y_min) - plot.YAxis.Min = flip_y ? plot_tl.y : plot_br.y; - if (!lock_y_max) - plot.YAxis.Max = flip_y ? plot_br.y : plot_tl.y; + for (int i = 0; i < MAX_Y_AXES; i++) { + if (!y[i].lock && plot.YAxis[i].Dragging) { + ImVec2 plot_tl = PixelsToPlot(gp.BB_Grid.Min - IO.MouseDelta, i); + ImVec2 plot_br = PixelsToPlot(gp.BB_Grid.Max - IO.MouseDelta, i); + + if (!y[i].lock_min) + plot.YAxis[i].Range.Min = y[i].flip ? plot_tl.y : plot_br.y; + if (!y[i].lock_max) + plot.YAxis[i].Range.Max = y[i].flip ? plot_br.y : plot_tl.y; + } } - if ((lock_x && lock_y) || (lock_x && plot.XAxis.Dragging && !plot.YAxis.Dragging) || (lock_y && plot.YAxis.Dragging && !plot.XAxis.Dragging)) + // Set the mouse cursor based on which axes are moving. + int direction = 0; + if (!x.lock && plot.XAxis.Dragging) { + direction |= (1 << 1); + } + for (int i = 0; i < MAX_Y_AXES; i++) { + if (!y[i].present) { continue; } + if (!y[i].lock && plot.YAxis[i].Dragging) { + direction |= (1 << 2); + break; + } + } + + if (direction == 0) { ImGui::SetMouseCursor(ImGuiMouseCursor_NotAllowed); - else if (lock_x || (!plot.XAxis.Dragging && plot.YAxis.Dragging)) - ImGui::SetMouseCursor(ImGuiMouseCursor_ResizeNS); - else if (lock_y || (!plot.YAxis.Dragging && plot.XAxis.Dragging)) + } else if (direction == (1 << 1)) { ImGui::SetMouseCursor(ImGuiMouseCursor_ResizeEW); - else + } else if (direction == (1 << 2)) { + ImGui::SetMouseCursor(ImGuiMouseCursor_ResizeNS); + } else { ImGui::SetMouseCursor(ImGuiMouseCursor_ResizeAll); + } } // start drag - if (gp.Hov_Frame && hov_x_axis_region && IO.MouseDragMaxDistanceSqr[0] > 5 && !plot.Selecting && !hov_legend && !hov_query && !plot.DraggingQuery) - plot.XAxis.Dragging = true; - if (gp.Hov_Frame && hov_y_axis_region && IO.MouseDragMaxDistanceSqr[0] > 5 && !plot.Selecting && !hov_legend && !hov_query && !plot.DraggingQuery) - plot.YAxis.Dragging = true; + 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; + } + for (int i = 0; i < MAX_Y_AXES; i++) { + if (hov_y_axis_region[i]) { + plot.YAxis[i].Dragging = true; + } + } + } // SCROLL INPUT ----------------------------------------------------------- - if (gp.Hov_Frame && (hov_x_axis_region || hov_y_axis_region) && IO.MouseWheel != 0) { + if (gp.Hov_Frame && (hov_x_axis_region || any_hov_y_axis_region) && IO.MouseWheel != 0) { UpdateTransformCache(); float zoom_rate = 0.1f; if (IO.MouseWheel > 0) zoom_rate = (-zoom_rate) / (1.0f + (2.0f * zoom_rate)); float tx = Remap(IO.MousePos.x, gp.BB_Grid.Min.x, gp.BB_Grid.Max.x, 0, 1); float ty = Remap(IO.MousePos.y, gp.BB_Grid.Min.y, gp.BB_Grid.Max.y, 0, 1); - ImVec2 plot_tl = PixelsToPlot(gp.BB_Grid.Min - gp.BB_Grid.GetSize() * ImVec2(tx * zoom_rate, ty * zoom_rate)); - ImVec2 plot_br = PixelsToPlot(gp.BB_Grid.Max + gp.BB_Grid.GetSize() * ImVec2((1 - tx) * zoom_rate, (1 - ty) * zoom_rate)); - if (hov_x_axis_region && !lock_x) { - if (!lock_x_min) - plot.XAxis.Min = flip_x ? plot_br.x : plot_tl.x; - if (!lock_x_max) - plot.XAxis.Max = flip_x ? plot_tl.x : plot_br.x; - } - if (hov_y_axis_region && !lock_y) { - if (!lock_y_min) - plot.YAxis.Min = flip_y ? plot_tl.y : plot_br.y; - if (!lock_y_max) - plot.YAxis.Max = flip_y ? plot_br.y : plot_tl.y; + if (hov_x_axis_region && !x.lock) { + ImRect axis_scale = GetAxisScale(0, tx, ty, zoom_rate); + const ImVec2& plot_tl = axis_scale.Min; + const ImVec2& plot_br = axis_scale.Max; + + if (!x.lock_min) + plot.XAxis.Range.Min = x.flip ? plot_br.x : plot_tl.x; + if (!x.lock_max) + plot.XAxis.Range.Max = x.flip ? plot_tl.x : plot_br.x; + } + for (int i = 0; i < MAX_Y_AXES; i++) { + if (hov_y_axis_region[i] && !y[i].lock) { + ImRect axis_scale = GetAxisScale(i, tx, ty, zoom_rate); + const ImVec2& plot_tl = axis_scale.Min; + const ImVec2& plot_br = axis_scale.Max; + + if (!y[i].lock_min) + plot.YAxis[i].Range.Min = y[i].flip ? plot_tl.y : plot_br.y; + if (!y[i].lock_max) + plot.YAxis[i].Range.Max = y[i].flip ? plot_br.y : plot_tl.y; + } } } @@ -878,14 +1142,18 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons if (HasFlag(plot.Flags, ImPlotFlags_Selection) && ImFabs(select_size.x) > 2 && ImFabs(select_size.y) > 2) { ImVec2 p1 = PixelsToPlot(plot.SelectStart); ImVec2 p2 = PixelsToPlot(IO.MousePos); - if (!lock_x_min && !IO.KeyAlt) - plot.XAxis.Min = ImMin(p1.x, p2.x); - if (!lock_x_max && !IO.KeyAlt) - plot.XAxis.Max = ImMax(p1.x, p2.x); - if (!lock_y_min && !IO.KeyShift) - plot.YAxis.Min = ImMin(p1.y, p2.y); - if (!lock_y_max && !IO.KeyShift) - plot.YAxis.Max = ImMax(p1.y, p2.y); + if (!x.lock_min && !IO.KeyAlt) + plot.XAxis.Range.Min = ImMin(p1.x, p2.x); + 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) + plot.YAxis[i].Range.Max = ImMax(p1.y, p2.y); + } } plot.Selecting = false; } @@ -909,14 +1177,9 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons plot.QueryRect.Max.x = IO.KeyAlt ? gp.BB_Grid.Max.x : ImMax(plot.QueryStart.x, IO.MousePos.x); plot.QueryRect.Min.y = IO.KeyShift ? gp.BB_Grid.Min.y : ImMin(plot.QueryStart.y, IO.MousePos.y); plot.QueryRect.Max.y = IO.KeyShift ? gp.BB_Grid.Max.y : ImMax(plot.QueryStart.y, IO.MousePos.y); - ImVec2 p1 = PixelsToPlot(plot.QueryRect.Min); - ImVec2 p2 = PixelsToPlot(plot.QueryRect.Max); + plot.QueryRect.Min -= gp.BB_Grid.Min; plot.QueryRect.Max -= gp.BB_Grid.Min; - plot.QueryRange.XMin = ImMin(p1.x, p2.x); - plot.QueryRange.XMax = ImMax(p1.x, p2.x); - plot.QueryRange.YMin = ImMin(p1.y, p2.y); - plot.QueryRange.YMax = ImMax(p1.y, p2.y); } // end query if (plot.Querying && (IO.MouseReleased[2] || IO.MouseReleased[1])) { @@ -926,45 +1189,45 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons } else { plot.Queried = false; - plot.QueryRange = ImPlotRange(); } } // 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.QueryRange = ImPlotRange(); 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.QueryRange = ImPlotRange(); 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; plot.QueryRect = ImRect(0,0,0,0); - plot.QueryRange = ImPlotRange(); } // DOUBLE CLICK ----------------------------------------------------------- - if ( IO.MouseDoubleClicked[0] && gp.Hov_Frame && (hov_x_axis_region || hov_y_axis_region) && !hov_legend && !hov_query) { + if ( IO.MouseDoubleClicked[0] && gp.Hov_Frame && (hov_x_axis_region || any_hov_y_axis_region) && !hov_legend && !hov_query) { gp.FitThisFrame = true; gp.FitX = hov_x_axis_region; - gp.FitY = hov_y_axis_region; + for (int i = 0; i < MAX_Y_AXES; i++) { + gp.FitY[i] = hov_y_axis_region[i]; + } } else { gp.FitThisFrame = false; gp.FitX = false; - gp.FitY = false; + for (int i = 0; i < MAX_Y_AXES; i++) { + gp.FitY[i] = false; + } } // FOCUS ------------------------------------------------------------------ @@ -976,7 +1239,9 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons UpdateTransformCache(); // set mouse position - gp.LastMousePos = PixelsToPlot(IO.MousePos); + for (int i = 0; i < MAX_Y_AXES; i++) { + gp.LastMousePos[i] = PixelsToPlot(IO.MousePos, i); + } // RENDER ----------------------------------------------------------------- @@ -988,23 +1253,27 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons // transform ticks if (gp.RenderX) { - for (auto& xt : gp.XTicks) - xt.PixelPos = PlotToPixels((float)xt.PlotPos, 0).x; + for (ImTick& xt : gp.XTicks) + xt.PixelPos = PlotToPixels((float)xt.PlotPos, 0, 0).x; } - if (gp.RenderY) { - for (auto& yt : gp.YTicks) - yt.PixelPos = PlotToPixels(0, (float)yt.PlotPos).y; + for (int i = 0; i < MAX_Y_AXES; i++) { + if (gp.RenderY[i]) { + for (ImTick& yt : gp.YTicks[i]) + yt.PixelPos = PlotToPixels(0, (float)yt.PlotPos, i).y; + } } // render grid if (HasFlag(plot.XAxis.Flags, ImAxisFlags_GridLines)) { - for (auto &xt : gp.XTicks) - DrawList.AddLine({xt.PixelPos, gp.BB_Grid.Min.y}, {xt.PixelPos, gp.BB_Grid.Max.y}, xt.Major ? gp.Col_XMajor : gp.Col_XMinor, 1); + for (ImTick &xt : gp.XTicks) + DrawList.AddLine({xt.PixelPos, gp.BB_Grid.Min.y}, {xt.PixelPos, gp.BB_Grid.Max.y}, xt.Major ? gp.Col_X.Major : gp.Col_X.Minor, 1); } - if (HasFlag(plot.YAxis.Flags, ImAxisFlags_GridLines)) { - for (auto &yt : gp.YTicks) - DrawList.AddLine({gp.BB_Grid.Min.x, yt.PixelPos}, {gp.BB_Grid.Max.x, yt.PixelPos}, yt.Major ? gp.Col_YMajor : gp.Col_YMinor, 1); + for (int i = 0; i < MAX_Y_AXES; i++) { + if (y[i].present && HasFlag(plot.YAxis[i].Flags, ImAxisFlags_GridLines)) { + for (ImTick &yt : gp.YTicks[i]) + DrawList.AddLine({gp.BB_Grid.Min.x, yt.PixelPos}, {gp.BB_Grid.Max.x, yt.PixelPos}, yt.Major ? gp.Col_Y[i].Major : gp.Col_Y[i].Minor, 1); + } } PopPlotClipRect(); @@ -1017,9 +1286,9 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons // render labels if (HasFlag(plot.XAxis.Flags, ImAxisFlags_TickLabels)) { PushClipRect(gp.BB_Frame.Min, gp.BB_Frame.Max, true); - for (auto &xt : gp.XTicks) { + for (ImTick &xt : gp.XTicks) { if (xt.RenderLabel && xt.PixelPos >= gp.BB_Grid.Min.x - 1 && xt.PixelPos <= gp.BB_Grid.Max.x + 1) - DrawList.AddText({xt.PixelPos - xt.Size.x * 0.5f, gp.BB_Grid.Max.y + txt_off}, gp.Col_XTxt, gp.XTickLabels.Buf.Data + xt.TextOffset); + DrawList.AddText({xt.PixelPos - xt.Size.x * 0.5f, gp.BB_Grid.Max.y + txt_off}, gp.Col_X.Txt, gp.XTickLabels.Buf.Data + xt.TextOffset); } ImGui::PopClipRect(); } @@ -1027,20 +1296,29 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons const ImVec2 xLabel_size = CalcTextSize(x_label); const ImVec2 xLabel_pos(gp.BB_Grid.GetCenter().x - xLabel_size.x * 0.5f, gp.BB_Canvas.Max.y - txt_height); - DrawList.AddText(xLabel_pos, gp.Col_XTxt, x_label); + DrawList.AddText(xLabel_pos, gp.Col_X.Txt, x_label); } - if (HasFlag(plot.YAxis.Flags, ImAxisFlags_TickLabels)) { - PushClipRect(gp.BB_Frame.Min, gp.BB_Frame.Max, true); - for (auto &yt : gp.YTicks) { - if (yt.RenderLabel && yt.PixelPos >= gp.BB_Grid.Min.y - 1 && yt.PixelPos <= gp.BB_Grid.Max.y + 1) - DrawList.AddText({gp.BB_Grid.Min.x - txt_off - yt.Size.x, yt.PixelPos - 0.5f * yt.Size.y}, gp.Col_YTxt, gp.YTickLabels.Buf.Data + yt.TextOffset); + 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 float x_start = + gp.AxisLabelReference[i] + + ((i == 0) ? + (-txt_off - max_label_width[0]) : + txt_off); + for (ImTick &yt : gp.YTicks[i]) { + if (yt.RenderLabel && yt.PixelPos >= gp.BB_Grid.Min.y - 1 && yt.PixelPos <= gp.BB_Grid.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); + } + } } - ImGui::PopClipRect(); } + ImGui::PopClipRect(); if (y_label) { const ImVec2 yLabel_size = CalcTextSizeVertical(y_label); const ImVec2 yLabel_pos(gp.BB_Canvas.Min.x, gp.BB_Grid.GetCenter().y + yLabel_size.y * 0.5f); - AddTextVertical(&DrawList, y_label, yLabel_pos, gp.Col_YTxt); + AddTextVertical(&DrawList, y_label, yLabel_pos, gp.Col_Y[0].Txt); } // PREP ------------------------------------------------------------------- @@ -1050,10 +1328,12 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons // reset items count gp.VisibleItemCount = 0; // reset extents - gp.Extents.Min.x = INFINITY; - gp.Extents.Min.y = INFINITY; - gp.Extents.Max.x = -INFINITY; - gp.Extents.Max.y = -INFINITY; + gp.ExtentsX.Min = INFINITY; + gp.ExtentsX.Max = -INFINITY; + for (int i = 0; i < MAX_Y_AXES; i++) { + gp.ExtentsY[i].Min = INFINITY; + gp.ExtentsY[i].Max = -INFINITY; + } // clear item names gp.LegendLabels.Buf.resize(0); // reset digital plot items count @@ -1082,7 +1362,7 @@ inline void AxisMenu(ImPlotAxis& Axis) { ImGui::PushItemFlag(ImGuiItemFlags_Disabled, true); ImGui::PushStyleVar(ImGuiStyleVar_Alpha, ImGui::GetStyle().Alpha * 0.25f); } - ImGui::DragFloat("Min", &Axis.Min, 0.01f + 0.01f * (Axis.Max - Axis.Min), -INFINITY, Axis.Max - FLT_EPSILON); + ImGui::DragFloat("Min", &Axis.Range.Min, 0.01f + 0.01f * (Axis.Range.Size()), -INFINITY, Axis.Range.Max - FLT_EPSILON); if (lock_min) { ImGui::PopItemFlag(); ImGui::PopStyleVar(); } @@ -1093,7 +1373,7 @@ inline void AxisMenu(ImPlotAxis& Axis) { if (lock_max) { ImGui::PushItemFlag(ImGuiItemFlags_Disabled, true); ImGui::PushStyleVar(ImGuiStyleVar_Alpha, ImGui::GetStyle().Alpha * 0.25f); } - ImGui::DragFloat("Max", &Axis.Max, 0.01f + 0.01f * (Axis.Max - Axis.Min), Axis.Min + FLT_EPSILON, INFINITY); + ImGui::DragFloat("Max", &Axis.Range.Max, 0.01f + 0.01f * (Axis.Range.Size()), Axis.Range.Min + FLT_EPSILON, INFINITY); if (lock_max) { ImGui::PopItemFlag(); ImGui::PopStyleVar(); @@ -1119,20 +1399,32 @@ void PlotContextMenu(ImPlot& plot) { PopID(); ImGui::EndMenu(); } - if (ImGui::BeginMenu("Y-Axis")) { - PushID("Y"); - AxisMenu(plot.YAxis); - PopID(); - ImGui::EndMenu(); + for (int i = 0; i < MAX_Y_AXES; i++) { + if (i == 1 && !HasFlag(plot.Flags, ImPlotFlags_YAxis2)) { + continue; + } + if (i == 2 && !HasFlag(plot.Flags, ImPlotFlags_YAxis3)) { + continue; + } + char buf[10] = {}; + if (i == 0) { + snprintf(buf, sizeof(buf) - 1, "Y-Axis"); + } else { + snprintf(buf, sizeof(buf) - 1, "Y-Axis %d", i + 1); + } + if (ImGui::BeginMenu(buf)) { + PushID(i); + AxisMenu(plot.YAxis[i]); + PopID(); + ImGui::EndMenu(); + } } + ImGui::Separator(); if ((ImGui::BeginMenu("Settings"))) { if (ImGui::MenuItem("Box Select",NULL,HasFlag(plot.Flags, ImPlotFlags_Selection))) { FlipFlag(plot.Flags, ImPlotFlags_Selection); } - if (ImGui::MenuItem("Pixel Query",NULL,HasFlag(plot.Flags, ImPlotFlags_PixelQuery))) { - FlipFlag(plot.Flags, ImPlotFlags_PixelQuery); - } if (ImGui::MenuItem("Crosshairs",NULL,HasFlag(plot.Flags, ImPlotFlags_Crosshairs))) { FlipFlag(plot.Flags, ImPlotFlags_Crosshairs); } @@ -1163,6 +1455,30 @@ void PlotContextMenu(ImPlot& plot) { } +namespace { +class BufferWriter { + public: + BufferWriter(char* buffer, size_t size) : Buffer(buffer), Pos(0), Size(size) {} + + void Write(const char* fmt, ...) IM_FMTARGS(2) { + va_list argp; + va_start(argp, fmt); + VWrite(fmt, argp); + va_end(argp); + } + + private: + void VWrite(const char* fmt, va_list argp) { + const int written = ::vsnprintf(&Buffer[Pos], Size - Pos - 1, fmt, argp); + Pos += written; + } + + char* const Buffer; + size_t Pos; + const size_t Size; +}; +} + //----------------------------------------------------------------------------- // EndPlot() //----------------------------------------------------------------------------- @@ -1179,30 +1495,63 @@ void EndPlot() { // AXIS STATES ------------------------------------------------------------ - const bool lock_x_min = HasFlag(plot.XAxis.Flags, ImAxisFlags_LockMin); - const bool lock_x_max = HasFlag(plot.XAxis.Flags, ImAxisFlags_LockMax); - const bool lock_x = (lock_x_min && lock_x_max) || (gp.NextPlotData.HasXRange && gp.NextPlotData.XRangeCond == ImGuiCond_Always); + 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.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_y_min = HasFlag(plot.YAxis.Flags, ImAxisFlags_LockMin); - const bool lock_y_max = HasFlag(plot.YAxis.Flags, ImAxisFlags_LockMax); - const bool lock_y = (lock_y_min && lock_y_max) || (gp.NextPlotData.HasYRange && gp.NextPlotData.YRangeCond == ImGuiCond_Always); - - const bool lock_plot = lock_x && lock_y; + 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; + const bool any_y_dragging = plot.YAxis[0].Dragging || plot.YAxis[1].Dragging || plot.YAxis[2].Dragging; // FINAL RENDER ----------------------------------------------------------- - PushPlotClipRect(); + PushClipRect(gp.BB_Grid.Min, gp.BB_Frame.Max, true); // render ticks + PushPlotClipRect(); if (HasFlag(plot.XAxis.Flags, ImAxisFlags_TickMarks)) { - for (auto &xt : gp.XTicks) + 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); } - if (HasFlag(plot.YAxis.Flags, ImAxisFlags_TickMarks)) { - for (auto &yt : gp.YTicks) - DrawList.AddLine({gp.BB_Grid.Min.x, yt.PixelPos}, {gp.BB_Grid.Min.x + (yt.Major ? 10.0f : 5.0f), yt.PixelPos}, 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; } + axis_count++; + + if (!HasFlag(plot.YAxis[i].Flags, ImAxisFlags_TickMarks)) { continue; } + + float x_start = gp.AxisLabelReference[i]; + float direction = (i == 0) ? 1.0f : -1.0f; + bool no_major = axis_count >= 3; + + for (ImTick &yt : gp.YTicks[i]) { + ImVec2 start = ImVec2(x_start, yt.PixelPos); + + DrawList.AddLine( + start, + start + ImVec2(direction * ((!no_major && yt.Major) ? 10.0f : 5.0f), 0), + gp.Col_Border, 1); + } + + if (axis_count >= 3) { + // Draw a bar next to the ticks to act as a visual separator. + DrawList.AddLine( + ImVec2(x_start, gp.BB_Grid.Min.y), + ImVec2(x_start, gp.BB_Grid.Max.y), + gp.Col_Border, 1); + } } + PopClipRect(); + + PushPlotClipRect(); // render selection/query if (plot.Selecting) { ImRect select_bb(ImMin(IO.MousePos, plot.SelectStart), ImMax(IO.MousePos, plot.SelectStart)); @@ -1211,11 +1560,11 @@ void EndPlot() { DrawList.AddRectFilled(gp.BB_Grid.Min, gp.BB_Grid.Max, gp.Col_SlctBg); DrawList.AddRect( gp.BB_Grid.Min, gp.BB_Grid.Max, gp.Col_SlctBd); } - else if ((lock_x || IO.KeyAlt) && select_bb.GetHeight() > 2) { + else if ((x.lock || IO.KeyAlt) && select_bb.GetHeight() > 2) { DrawList.AddRectFilled(ImVec2(gp.BB_Grid.Min.x, select_bb.Min.y), ImVec2(gp.BB_Grid.Max.x, select_bb.Max.y), gp.Col_SlctBg); DrawList.AddRect( ImVec2(gp.BB_Grid.Min.x, select_bb.Min.y), ImVec2(gp.BB_Grid.Max.x, select_bb.Max.y), gp.Col_SlctBd); } - else if ((lock_y || IO.KeyShift) && select_bb.GetWidth() > 2) { + else if ((any_y_locked || IO.KeyShift) && select_bb.GetWidth() > 2) { DrawList.AddRectFilled(ImVec2(select_bb.Min.x, gp.BB_Grid.Min.y), ImVec2(select_bb.Max.x, gp.BB_Grid.Max.y), gp.Col_SlctBg); DrawList.AddRect( ImVec2(select_bb.Min.x, gp.BB_Grid.Min.y), ImVec2(select_bb.Max.x, gp.BB_Grid.Max.y), gp.Col_SlctBd); } @@ -1226,19 +1575,59 @@ void EndPlot() { } } - if (plot.Querying || (HasFlag(plot.Flags, ImPlotFlags_PixelQuery) && plot.Queried)) { + if (plot.Querying || plot.Queried) { if (plot.QueryRect.GetWidth() > 2 && plot.QueryRect.GetHeight() > 2) { DrawList.AddRectFilled(plot.QueryRect.Min + gp.BB_Grid.Min, plot.QueryRect.Max + gp.BB_Grid.Min, gp.Col_QryBg); DrawList.AddRect( plot.QueryRect.Min + gp.BB_Grid.Min, plot.QueryRect.Max + gp.BB_Grid.Min, gp.Col_QryBd); } } else if (plot.Queried) { - ImVec2 p1 = PlotToPixels(plot.QueryRange.XMin, plot.QueryRange.YMin); - ImVec2 p2 = PlotToPixels(plot.QueryRange.XMax, plot.QueryRange.YMax); - ImVec2 Min(ImMin(p1.x,p2.x), ImMin(p1.y,p2.y)); - ImVec2 Max(ImMax(p1.x,p2.x), ImMax(p1.y,p2.y)); - DrawList.AddRectFilled(Min, Max, gp.Col_QryBg); - DrawList.AddRect( Min, Max, gp.Col_QryBd); + ImRect bb_query = plot.QueryRect; + + bb_query.Min += gp.BB_Grid.Min; + bb_query.Max += gp.BB_Grid.Min; + + DrawList.AddRectFilled(bb_query.Min, bb_query.Max, gp.Col_QryBg); + DrawList.AddRect( bb_query.Min, bb_query.Max, gp.Col_QryBd); + } + + //render query x-axis + if (HasFlag(plot.Flags, ImPlotFlags_QueryX)) { + //render x1 + const int lineOffset = -1; + ImVec2 p1, p2; + p1.x = plot.QueryRectX[0].Min.x; + p1.y = plot.QueryRectX[0].Min.y; + p2 = p1 + ImVec2(3,10); + DrawList.AddRectFilled(p1, p2, gp.Col_QryX);//upper rectangle + p1.x = plot.QueryRectX[0].Min.x; + p1.y = plot.QueryRectX[0].Max.y; + p2 = p1 + ImVec2(3,-10); + DrawList.AddRectFilled(p1, p2, gp.Col_QryX);//lower rectangle + p1.x = plot.QueryRectX[0].Min.x; + p1.y = plot.QueryRectX[0].Min.y; + p1 += ImVec2(1, 10 -lineOffset); + p2.x = plot.QueryRectX[0].Min.x; + p2.y = plot.QueryRectX[0].Max.y; + p2 += ImVec2(1, -10 +lineOffset); + DrawList.AddLine(p1, p2, gp.Col_QryX);//line + + //render x2 + p1.x = plot.QueryRectX[1].Min.x; + p1.y = plot.QueryRectX[1].Min.y; + p2 = p1 + ImVec2(3,10); + DrawList.AddRectFilled(p1, p2, gp.Col_QryX);//upper rectangle + p1.x = plot.QueryRectX[1].Min.x; + p1.y = plot.QueryRectX[1].Max.y; + p2 = p1 + ImVec2(3,-10); + DrawList.AddRectFilled(p1, p2, gp.Col_QryX);//lower rectangle + p1.x = plot.QueryRectX[1].Min.x; + p1.y = plot.QueryRectX[1].Min.y; + p1 += ImVec2(1, 10 -lineOffset); + p2.x = plot.QueryRectX[1].Min.x; + p2.y = plot.QueryRectX[1].Max.y; + p2 += ImVec2(1, -10 +lineOffset); + DrawList.AddLine(p1, p2, gp.Col_QryX);//line } // render legend @@ -1254,7 +1643,7 @@ void EndPlot() { float max_label_width = 0; for (int i = 0; i < nItems; ++i) { const char* label = GetLegendLabel(i); - auto labelWidth = CalcTextSize(label, NULL, true); + ImVec2 labelWidth = CalcTextSize(label, NULL, true); max_label_width = labelWidth.x > max_label_width ? labelWidth.x : max_label_width; } legend_content_bb = ImRect(gp.BB_Grid.Min + legend_offset, gp.BB_Grid.Min + legend_offset + ImVec2(max_label_width, nItems * txt_ht)); @@ -1281,7 +1670,7 @@ void EndPlot() { item->Highlight = false; ImU32 iconColor; if (hov_legend && icon_bb.Contains(IO.MousePos)) { - auto colAlpha = item->Color; + ImVec4 colAlpha = item->Color; colAlpha.w = 0.5f; iconColor = item->Show ? GetColorU32(colAlpha) : GetColorU32(ImGuiCol_TextDisabled, 0.5f); @@ -1301,7 +1690,7 @@ void EndPlot() { // render crosshairs if (HasFlag(plot.Flags, ImPlotFlags_Crosshairs) && gp.Hov_Grid && gp.Hov_Frame && - !(plot.XAxis.Dragging || plot.YAxis.Dragging) && !plot.Selecting && !plot.Querying && !hov_legend) { + !(plot.XAxis.Dragging || any_y_dragging) && !plot.Selecting && !plot.Querying && !hov_legend) { ImGui::SetMouseCursor(ImGuiMouseCursor_None); ImVec2 xy = IO.MousePos; ImVec2 h1(gp.BB_Grid.Min.x, xy.y); @@ -1320,8 +1709,16 @@ void EndPlot() { // render mouse pos if (HasFlag(plot.Flags, ImPlotFlags_MousePos) && gp.Hov_Grid) { - static char buffer[128]; - sprintf(buffer, "%.2f,%.2f", gp.LastMousePos.x, gp.LastMousePos.y); + static char buffer[128] = {}; + BufferWriter writer(buffer, sizeof(buffer)); + + writer.Write("%.2f,%.2f", gp.LastMousePos[0].x, gp.LastMousePos[0].y); + if (HasFlag(plot.Flags, ImPlotFlags_YAxis2)) { + writer.Write(",(%.2f)", gp.LastMousePos[1].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); @@ -1335,14 +1732,20 @@ void EndPlot() { // FIT DATA -------------------------------------------------------------- if (gp.FitThisFrame && (gp.VisibleItemCount > 0 || plot.Queried)) { - if (gp.FitX && !HasFlag(plot.XAxis.Flags, ImAxisFlags_LockMin) && !NanOrInf(gp.Extents.Min.x)) - plot.XAxis.Min = gp.Extents.Min.x; - if (gp.FitX && !HasFlag(plot.XAxis.Flags, ImAxisFlags_LockMax) && !NanOrInf(gp.Extents.Max.x)) - plot.XAxis.Max = gp.Extents.Max.x; - if (gp.FitY && !HasFlag(plot.YAxis.Flags, ImAxisFlags_LockMin) && !NanOrInf(gp.Extents.Min.y)) - plot.YAxis.Min = gp.Extents.Min.y; - if (gp.FitY && !HasFlag(plot.YAxis.Flags, ImAxisFlags_LockMax) && !NanOrInf(gp.Extents.Max.y)) - plot.YAxis.Max = gp.Extents.Max.y; + if (gp.FitX && !HasFlag(plot.XAxis.Flags, ImAxisFlags_LockMin) && !NanOrInf(gp.ExtentsX.Min)) { + plot.XAxis.Range.Min = gp.ExtentsX.Min; + } + if (gp.FitX && !HasFlag(plot.XAxis.Flags, ImAxisFlags_LockMax) && !NanOrInf(gp.ExtentsX.Max)) { + plot.XAxis.Range.Max = gp.ExtentsX.Max; + } + for (int i = 0; i < MAX_Y_AXES; i++) { + if (gp.FitY[i] && !HasFlag(plot.YAxis[i].Flags, ImAxisFlags_LockMin) && !NanOrInf(gp.ExtentsY[i].Min)) { + plot.YAxis[i].Range.Min = gp.ExtentsY[i].Min; + } + if (gp.FitY[i] && !HasFlag(plot.YAxis[i].Flags, ImAxisFlags_LockMax) && !NanOrInf(gp.ExtentsY[i].Max)) { + plot.YAxis[i].Range.Max = gp.ExtentsY[i].Max; + } + } } // CONTEXT MENU ----------------------------------------------------------- @@ -1372,25 +1775,32 @@ void EndPlot() { // MISC API //----------------------------------------------------------------------------- -void SetNextPlotRange(float x_min, float x_max, float y_min, float y_max, ImGuiCond cond) { - SetNextPlotRangeX(x_min, x_max, cond); - SetNextPlotRangeY(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 SetNextPlotRangeX(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.HasXRange = true; gp.NextPlotData.XRangeCond = cond; - gp.NextPlotData.XMin = x_min; - gp.NextPlotData.XMax = x_max; + gp.NextPlotData.X.Min = x_min; + gp.NextPlotData.X.Max = x_max; } -void SetNextPlotRangeY(float y_min, float y_max, ImGuiCond cond) { +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.HasYRange = true; - gp.NextPlotData.YRangeCond = cond; - gp.NextPlotData.YMin = y_min; - gp.NextPlotData.YMax = y_max; + 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; +} + +void SetPlotYAxis(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_USER_ERROR(gp.CurrentPlot != NULL, "SetPlotYAxis() Needs to be called between BeginPlot() and EndPlot()!"); + gp.CurrentPlot->CurrentYAxis = y_axis; } ImVec2 GetPlotPos() { @@ -1416,21 +1826,24 @@ bool IsPlotHovered() { IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "IsPlotHovered() Needs to be called between BeginPlot() and EndPlot()!"); return gp.Hov_Grid; } -ImVec2 GetPlotMousePos() { +ImVec2 GetPlotMousePos(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, "GetPlotMousePos() Needs to be called between BeginPlot() and EndPlot()!"); - return gp.LastMousePos; + const int y_axis = y_axis_in >= 0 ? y_axis_in : gp.CurrentPlot->CurrentYAxis; + return gp.LastMousePos[y_axis]; } -ImPlotRange GetPlotRange() { - IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "GetPlotRange() Needs to be called between BeginPlot() and EndPlot()!"); +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, "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; - ImPlotRange range; - range.XMin = plot.XAxis.Min; - range.XMax = plot.XAxis.Max; - range.YMin = plot.YAxis.Min; - range.YMax = plot.YAxis.Max; - return range; + ImPlotLimits limits; + limits.X = plot.XAxis.Range; + limits.Y = plot.YAxis[y_axis].Range; + return limits; } bool IsPlotQueried() { @@ -1438,21 +1851,35 @@ bool IsPlotQueried() { return gp.CurrentPlot->Queried; } -ImPlotRange GetPlotQuery() { +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; - if (HasFlag(plot.Flags, ImPlotFlags_PixelQuery)) { - UpdateTransformCache(); - ImVec2 p1 = PixelsToPlot(plot.QueryRect.Min + gp.BB_Grid.Min); - ImVec2 p2 = PixelsToPlot(plot.QueryRect.Max + gp.BB_Grid.Min); - plot.QueryRange.XMin = ImMin(p1.x, p2.x); - plot.QueryRange.XMax = ImMax(p1.x, p2.x); - plot.QueryRange.YMin = ImMin(p1.y, p2.y); - plot.QueryRange.YMax = ImMax(p1.y, p2.y); - } - return plot.QueryRange; + const int y_axis = y_axis_in >= 0 ? y_axis_in : gp.CurrentPlot->CurrentYAxis; + + UpdateTransformCache(); + ImVec2 p1 = PixelsToPlot(plot.QueryRect.Min + gp.BB_Grid.Min, y_axis); + ImVec2 p2 = PixelsToPlot(plot.QueryRect.Max + gp.BB_Grid.Min, y_axis); + + 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; } +ImPlotLimits GetPlotQueryX() { + IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "GetPlotQueryX() Needs to be called between BeginPlot() and EndPlot()!"); + ImPlot& plot = *gp.CurrentPlot; + ImVec2 x1 = plot.QueryRectX[0].Min; + ImVec2 x2 = plot.QueryRectX[1].Min; + x1.x += 1; + x2.x += 1; + plot.QueryRangeX.X.Min = PixelsToPlot(x1).x; + plot.QueryRangeX.X.Max = PixelsToPlot(x2).x; + return plot.QueryRangeX; +} //----------------------------------------------------------------------------- // STYLING //----------------------------------------------------------------------------- @@ -1610,7 +2037,7 @@ inline void MarkerGeneral(ImDrawList& DrawList, ImVec2* points, int n, const ImV } } -inline void MakerCircle(ImDrawList& DrawList, const ImVec2& c, float s, bool outline, ImU32 col_outline, bool fill, ImU32 col_fill, float weight) { +inline void MarkerCircle(ImDrawList& DrawList, const ImVec2& c, float s, bool outline, ImU32 col_outline, bool fill, ImU32 col_fill, float weight) { ImVec2 marker[10] = {{1.0f, 0.0f}, {0.809017f, 0.58778524f}, {0.30901697f, 0.95105654f}, @@ -1677,16 +2104,16 @@ inline void MarkerCross(ImDrawList& DrawList, const ImVec2& c, float s, bool out } template -inline void RenderMarkers(ImDrawList& DrawList, Getter getter, int count, int offset, bool rend_mk_line, ImU32 col_mk_line, bool rend_mk_fill, ImU32 col_mk_fill, bool cull) { +inline void RenderMarkers(Transformer transformer, ImDrawList& DrawList, Getter getter, int count, int offset, bool rend_mk_line, ImU32 col_mk_line, bool rend_mk_fill, ImU32 col_mk_fill, bool cull) { int idx = offset; for (int i = 0; i < count; ++i) { ImVec2 c; - c = Transformer::Transform(getter(idx)); + c = transformer(getter(idx)); idx = (idx + 1) % count; if (!cull || gp.BB_Grid.Contains(c)) { // TODO: Optimize the loop and if statements, this is atrocious if (HasFlag(gp.Style.Marker, ImMarker_Circle)) - MakerCircle(DrawList, c, gp.Style.MarkerSize, rend_mk_line, col_mk_line, rend_mk_fill, col_mk_fill, gp.Style.MarkerWeight); + MarkerCircle(DrawList, c, gp.Style.MarkerSize, rend_mk_line, col_mk_line, rend_mk_fill, col_mk_fill, gp.Style.MarkerWeight); if (HasFlag(gp.Style.Marker, ImMarker_Square)) MarkerSquare(DrawList, c, gp.Style.MarkerSize, rend_mk_line, col_mk_line, rend_mk_fill, col_mk_fill, gp.Style.MarkerWeight); if (HasFlag(gp.Style.Marker, ImMarker_Diamond)) @@ -1748,7 +2175,7 @@ inline void RenderLineAA(ImDrawList& DrawList, const ImVec2& p1, const ImVec2& p } template -inline void RenderLines(ImDrawList& DrawList, Getter getter, int count, int offset, float line_weight, ImU32 col_line, bool cull) { +inline void RenderLines(Transformer transformer, ImDrawList& DrawList, Getter getter, int count, int offset, float line_weight, ImU32 col_line, bool cull) { // render line segments const int segments = count - 1; int i1 = offset; @@ -1756,8 +2183,8 @@ inline void RenderLines(ImDrawList& DrawList, Getter getter, int count, int offs if (HasFlag(gp.CurrentPlot->Flags, ImPlotFlags_AntiAliased)) { for (int s = 0; s < segments; ++s) { const int i2 = (i1 + 1) % count; - p1 = Transformer::Transform(getter(i1)); - p2 = Transformer::Transform(getter(i2)); + p1 = transformer(getter(i1)); + p2 = transformer(getter(i2)); i1 = i2; if (!cull || gp.BB_Grid.Contains(p1) || gp.BB_Grid.Contains(p2)) RenderLineAA(DrawList, p1, p2, line_weight, col_line); @@ -1769,8 +2196,8 @@ inline void RenderLines(ImDrawList& DrawList, Getter getter, int count, int offs int segments_culled = 0; for (int s = 0; s < segments; ++s) { const int i2 = (i1 + 1) % count; - p1 = Transformer::Transform(getter(i1)); - p2 = Transformer::Transform(getter(i2)); + p1 = transformer(getter(i1)); + p2 = transformer(getter(i2)); i1 = i2; if (!cull || gp.BB_Grid.Contains(p1) || gp.BB_Grid.Contains(p2)) RenderLine(DrawList, p1, p2, line_weight, col_line, uv); @@ -1838,6 +2265,8 @@ inline void PlotEx(const char* label_id, Getter getter, int count, int offset) { IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "Plot() Needs to be called between BeginPlot() and EndPlot()!"); + ImPlot* plot = gp.CurrentPlot; + const int y_axis = plot->CurrentYAxis; ImPlotItem* item = RegisterItem(label_id); if (!item->Show) return; @@ -1857,7 +2286,7 @@ inline void PlotEx(const char* label_id, Getter getter, int count, int offset) if (gp.Style.Colors[ImPlotCol_Line].w != -1) item->Color = gp.Style.Colors[ImPlotCol_Line]; - bool cull = HasFlag(gp.CurrentPlot->Flags, ImPlotFlags_CullData); + bool cull = HasFlag(plot->Flags, ImPlotFlags_CullData); // find data extents if (gp.FitThisFrame) { @@ -1868,25 +2297,25 @@ inline void PlotEx(const char* label_id, Getter getter, int count, int offset) } PushPlotClipRect(); if (count > 1 && rend_line) { - if (HasFlag(gp.CurrentPlot->XAxis.Flags, ImAxisFlags_LogScale) && HasFlag(gp.CurrentPlot->YAxis.Flags, ImAxisFlags_LogScale)) - RenderLines(DrawList, getter, count, offset, line_weight, col_line, cull); - else if (HasFlag(gp.CurrentPlot->XAxis.Flags, ImAxisFlags_LogScale)) - RenderLines(DrawList, getter, count, offset, line_weight, col_line, cull); - else if (HasFlag(gp.CurrentPlot->YAxis.Flags, ImAxisFlags_LogScale)) - RenderLines(DrawList, getter, count, offset, line_weight, col_line, cull); + if (HasFlag(plot->XAxis.Flags, ImAxisFlags_LogScale) && HasFlag(plot->YAxis[y_axis].Flags, ImAxisFlags_LogScale)) + RenderLines(Plt2PixLogLog(y_axis), DrawList, getter, count, offset, line_weight, col_line, cull); + else if (HasFlag(plot->XAxis.Flags, ImAxisFlags_LogScale)) + RenderLines(Plt2PixLogLin(y_axis), DrawList, getter, count, offset, line_weight, col_line, cull); + else if (HasFlag(plot->YAxis[y_axis].Flags, ImAxisFlags_LogScale)) + RenderLines(Plt2PixLinLog(y_axis), DrawList, getter, count, offset, line_weight, col_line, cull); else - RenderLines(DrawList, getter, count, offset, line_weight, col_line, cull); + RenderLines(Plt2PixLinLin(y_axis), DrawList, getter, count, offset, line_weight, col_line, cull); } // render markers if (gp.Style.Marker != ImMarker_None) { - if (HasFlag(gp.CurrentPlot->XAxis.Flags, ImAxisFlags_LogScale) && HasFlag(gp.CurrentPlot->YAxis.Flags, ImAxisFlags_LogScale)) - RenderMarkers(DrawList, getter, count, offset, rend_mk_line, col_mk_line, rend_mk_fill, col_mk_fill, cull); - else if (HasFlag(gp.CurrentPlot->XAxis.Flags, ImAxisFlags_LogScale)) - RenderMarkers(DrawList, getter, count, offset, rend_mk_line, col_mk_line, rend_mk_fill, col_mk_fill, cull); - else if (HasFlag(gp.CurrentPlot->YAxis.Flags, ImAxisFlags_LogScale)) - RenderMarkers(DrawList, getter, count, offset, rend_mk_line, col_mk_line, rend_mk_fill, col_mk_fill, cull); + if (HasFlag(plot->XAxis.Flags, ImAxisFlags_LogScale) && HasFlag(plot->YAxis[y_axis].Flags, ImAxisFlags_LogScale)) + RenderMarkers(Plt2PixLogLog(y_axis), DrawList, getter, count, offset, rend_mk_line, col_mk_line, rend_mk_fill, col_mk_fill, cull); + else if (HasFlag(plot->XAxis.Flags, ImAxisFlags_LogScale)) + RenderMarkers(Plt2PixLogLin(y_axis), DrawList, getter, count, offset, rend_mk_line, col_mk_line, rend_mk_fill, col_mk_fill, cull); + else if (HasFlag(plot->YAxis[y_axis].Flags, ImAxisFlags_LogScale)) + RenderMarkers(Plt2PixLinLog(y_axis), DrawList, getter, count, offset, rend_mk_line, col_mk_line, rend_mk_fill, col_mk_fill, cull); else - RenderMarkers(DrawList, getter, count, offset, rend_mk_line, col_mk_line, rend_mk_fill, col_mk_fill, cull); + RenderMarkers(Plt2PixLinLin(y_axis), DrawList, getter, count, offset, rend_mk_line, col_mk_line, rend_mk_fill, col_mk_fill, cull); } PopPlotClipRect(); } @@ -2240,10 +2669,13 @@ inline void PlotDigitalEx(const char* label_id, Getter getter, int count, int of bool cull = HasFlag(gp.CurrentPlot->Flags, ImPlotFlags_CullData); const float line_weight = item->Highlight ? gp.Style.LineWeight * 2 : gp.Style.LineWeight; + + const int ax = gp.CurrentPlot->CurrentYAxis; + // render digital signals as "pixel bases" rectangles if (count > 1 && rend_line) { // - const float mx = (gp.PixelRange.Max.x - gp.PixelRange.Min.x) / (gp.CurrentPlot->XAxis.Max - gp.CurrentPlot->XAxis.Min); + const float mx = (gp.PixelRange[ax].Max.x - gp.PixelRange[ax].Min.x) / gp.CurrentPlot->XAxis.Range.Size(); const int segments = count - 1; int i1 = offset; int pixYMax = 0; @@ -2257,28 +2689,28 @@ inline void PlotDigitalEx(const char* label_id, Getter getter, int count, int of int pixY_chPosOffset = ImMax((int)gp.Style.DigitalBitHeight, pixY_1) + gp.Style.DigitalBitGap; pixYMax = ImMax(pixYMax, pixY_chPosOffset); ImVec2 pMin, pMax; - pMin.x = gp.PixelRange.Min.x + mx * (itemData1.x - gp.CurrentPlot->XAxis.Min); - pMax.x = gp.PixelRange.Min.x + mx * (itemData2.x - gp.CurrentPlot->XAxis.Min); + pMin.x = gp.PixelRange[ax].Min.x + mx * (itemData1.x - gp.CurrentPlot->XAxis.Range.Min); + pMax.x = gp.PixelRange[ax].Min.x + mx * (itemData2.x - gp.CurrentPlot->XAxis.Range.Min); int pixY_Offset = 20;//20 pixel from bottom due to mouse cursor label - pMin.y = (gp.PixelRange.Min.y) + ((-gp.DigitalPlotOffset) - pixY_Offset); - pMax.y = (gp.PixelRange.Min.y) + ((-gp.DigitalPlotOffset) - pixY_0 - pixY_1 - pixY_Offset); + pMin.y = (gp.PixelRange[ax].Min.y) + ((-gp.DigitalPlotOffset) - pixY_Offset); + pMax.y = (gp.PixelRange[ax].Min.y) + ((-gp.DigitalPlotOffset) - pixY_0 - pixY_1 - pixY_Offset); //plot only one rectangle for same digital state while (((s+2) < segments) && (itemData1.y == itemData2.y)) { const int i2 = (i1 + 1) % count; itemData2 = getter(i2); - pMax.x = gp.PixelRange.Min.x + mx * (itemData2.x - gp.CurrentPlot->XAxis.Min); + pMax.x = gp.PixelRange[ax].Min.x + mx * (itemData2.x - gp.CurrentPlot->XAxis.Range.Min); i1 = i2; s++; } //do not extend plot outside plot range - if (pMin.x < gp.PixelRange.Min.x) pMin.x = gp.PixelRange.Min.x; - if (pMax.x < gp.PixelRange.Min.x) pMax.x = gp.PixelRange.Min.x; - if (pMin.x > gp.PixelRange.Max.x) pMin.x = gp.PixelRange.Max.x; - if (pMax.x > gp.PixelRange.Max.x) pMax.x = gp.PixelRange.Max.x; + if (pMin.x < gp.PixelRange[ax].Min.x) pMin.x = gp.PixelRange[ax].Min.x; + if (pMax.x < gp.PixelRange[ax].Min.x) pMax.x = gp.PixelRange[ax].Min.x; + if (pMin.x > gp.PixelRange[ax].Max.x) pMin.x = gp.PixelRange[ax].Max.x; + if (pMax.x > gp.PixelRange[ax].Max.x) pMax.x = gp.PixelRange[ax].Max.x; //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))) { - auto colAlpha = item->Color; - colAlpha.w = item->Highlight ? 1.0 : 0.9; + ImVec4 colAlpha = item->Color; + colAlpha.w = item->Highlight ? 1.0f : 0.9f; DrawList.AddRectFilled(pMin, pMax, GetColorU32(colAlpha)); } } From 41ece38678b77001125127c05f15c6239bbaf1b7 Mon Sep 17 00:00:00 2001 From: ozlb Date: Mon, 11 May 2020 13:13:08 +0200 Subject: [PATCH 03/11] PlotDigital updates on ImPlot v0.2 --- implot.h | 109 +++++++++++++++++++++++++++++++++---------------------- 1 file changed, 65 insertions(+), 44 deletions(-) diff --git a/implot.h b/implot.h index b6e41b4..2e18c5a 100644 --- a/implot.h +++ b/implot.h @@ -20,10 +20,10 @@ // 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 +#include "imgui.h" //----------------------------------------------------------------------------- // Basic types and flags @@ -37,16 +37,19 @@ typedef int ImMarker; // Options for plots enum ImPlotFlags_ { - ImPlotFlags_MousePos = 1 << 0, // the mouse position, in plot coordinates, will be displayed in the bottom-right - 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_PixelQuery = 1 << 4, // query ranges will not change their pixel position if the plot is scrolled/zoomed - 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_MousePos = 1 << 0, // the mouse position, in plot coordinates, will be displayed in the bottom-right + 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_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_QueryX = 1 << 12,// show x-axis query ImPlotFlags_Default = ImPlotFlags_MousePos | ImPlotFlags_Legend | ImPlotFlags_Highlight | ImPlotFlags_Selection | ImPlotFlags_ContextMenu | ImPlotFlags_CullData }; @@ -61,7 +64,8 @@ enum ImAxisFlags_ { ImAxisFlags_Adaptive = 1 << 6, // grid divisions will adapt to the current pixel size the axis 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_Default = ImAxisFlags_GridLines | ImAxisFlags_TickMarks | ImAxisFlags_TickLabels | ImAxisFlags_Adaptive, + ImAxisFlags_Auxiliary = ImAxisFlags_Default & ~ImAxisFlags_GridLines, }; // Plot styling colors @@ -74,13 +78,17 @@ 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, // x-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_QueryX, // x-axis query color (defaults to red) ImPlotCol_COUNT }; +// Plot styling variables enum ImPlotStyleVar_ { ImPlotStyleVar_LineWeight, // float, line weight in pixels ImPlotStyleVar_Marker, // int, marker specification @@ -108,11 +116,19 @@ enum ImMarker_ { ImMarker_Asterisk = 1 << 10, // a asterisk marker will be rendered at each point (not filled) }; -/// Plot range utility struct +// A range defined by a min/max value. Used for plot axes ranges. struct ImPlotRange { - float XMin, XMax, YMin, YMax; + float Min, Max; ImPlotRange(); - bool Contains(const ImVec2& p); + bool Contains(float value) const; + float Size() const; +}; + +// Combination of two ranges for X and Y axes. +struct ImPlotLimits { + ImPlotRange X, Y; + ImPlotLimits(); + bool Contains(const ImVec2& p) const; }; // Plot style structure @@ -139,15 +155,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. 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); + 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(); @@ -156,7 +173,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); @@ -187,15 +204,16 @@ void PlotDigital(const char* label_id, ImVec2 (*getter)(void* data, int idx), vo /// Returns true if the plot area in the current or most recent plot is hovered. bool IsPlotHovered(); -/// Returns the mouse position in x,y coordinates of the current or most recent plot. -ImVec2 GetPlotMousePos(); -/// Returns the current or most recent plot axis range. -ImPlotRange GetPlotRange(); +/// 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). +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 querey range. -ImPlotRange GetPlotQuery(); - +/// Returns the current or most recent plot query bounds. +ImPlotLimits GetPlotQuery(int y_axis = -1); +/// Returns the current x-axis query range. +ImPlotLimits GetPlotQueryX(); //----------------------------------------------------------------------------- // Plot Styling //----------------------------------------------------------------------------- @@ -226,22 +244,25 @@ 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 SetNextPlotRange(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 SetNextPlotRangeX(float x_min, float x_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 SetNextPlotRangeY(float y_min, float y_max, ImGuiCond cond = ImGuiCond_Once); +/// 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 y_axis); // Get the current Plot position (top-left) in pixels. ImVec2 GetPlotPos(); // Get the curent Plot size in pixels. ImVec2 GetPlotSize(); -// Convert pixels to a position in the current plot's coordinate system. -ImVec2 PixelsToPlot(const ImVec2& pix); -// Convert a position in the current plot's coordinate system to pixels. -ImVec2 PlotToPixels(const ImVec2& plt); +// Convert pixels to a position in the current plot's coordinate system. A negative y_axis uses the current value of SetPlotYAxis (0 initially). +ImVec2 PixelsToPlot(const ImVec2& pix, int y_axis = -1); +// 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 ImVec2& plt, int y_axis = -1); // Push clip rect for rendering to current plot area void PushPlotClipRect(); From 676906afae7623079df2fc6dc4bebf0bcab25afe Mon Sep 17 00:00:00 2001 From: ozlb Date: Mon, 11 May 2020 13:13:43 +0200 Subject: [PATCH 04/11] PlotDigital updates on ImPlot v0.2 WIP --- implot_demo.cpp | 143 +++++++++++++++++++++++++++++++++--------------- 1 file changed, 100 insertions(+), 43 deletions(-) diff --git a/implot_demo.cpp b/implot_demo.cpp index 6b540ac..1c87d99 100644 --- a/implot_demo.cpp +++ b/implot_demo.cpp @@ -20,11 +20,16 @@ // 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 -#include +#ifdef _MSC_VER +#pragma warning (disable: 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen +#endif + +#include "implot.h" #include #include +#include namespace { @@ -91,7 +96,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."); @@ -108,11 +113,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."); @@ -172,9 +172,9 @@ void ShowImPlotDemoWindow(bool* p_open) { static bool horz = false; ImGui::Checkbox("Horizontal",&horz); if (horz) - ImGui::SetNextPlotRange(0, 110, -0.5f, 9.5f, ImGuiCond_Always); + ImGui::SetNextPlotLimits(0, 110, -0.5f, 9.5f, ImGuiCond_Always); else - ImGui::SetNextPlotRange(-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}; @@ -199,7 +199,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::SetNextPlotRange(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); @@ -223,7 +223,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 - SetNextPlotRange(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(); @@ -238,7 +238,7 @@ void ShowImPlotDemoWindow(bool* p_open) { {0.7412f, 0.0f, 0.1490f, 1.0f}, }; ImGui::SetPlotPalette(YlOrRd, 5); - SetNextPlotRange(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)) { @@ -264,14 +264,14 @@ void ShowImPlotDemoWindow(bool* p_open) { sdata2.AddPoint(t, mouse.y * 0.0005f); rdata2.AddPoint(t, mouse.y * 0.0005f); } - ImGui::SetNextPlotRangeX(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::SetNextPlotRangeX(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)); @@ -281,7 +281,7 @@ void ShowImPlotDemoWindow(bool* p_open) { //------------------------------------------------------------------------- if (ImGui::CollapsingHeader("Markers and Labels")) { - ImGui::SetNextPlotRange(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}; @@ -365,7 +365,7 @@ void ShowImPlotDemoWindow(bool* p_open) { ys2[i] = log(xs[i]); ys3[i] = pow(10.0f, xs[i]); } - ImGui::SetNextPlotRange(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); @@ -375,13 +375,72 @@ void ShowImPlotDemoWindow(bool* p_open) { } } //------------------------------------------------------------------------- + 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.2f + 0.5f; + ys3[i] = sin(xs[i]+0.5f) * 100 + 200; + xs2[i] = xs[i] + 10.0f; + } + 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_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); + + if (y2_axis) { + ImGui::SetPlotYAxis(1); + ImGui::Plot("f(x) = cos(x)*.2+.5 (Y2)", xs, ys2, 1001); + } + + if (y3_axis) { + ImGui::SetPlotYAxis(2); + ImGui::Plot("f(x) = sin(x+.5)*100+200 (Y3)", xs2, ys3, 1001); + } + + ImGui::EndPlot(); + } + 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; - ImPlotRange 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); @@ -389,7 +448,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) { - ImPlotRange range = ImGui::GetPlotQuery(); + ImPlotLimits range = ImGui::GetPlotQuery(); int cnt = 0; ImVec2 avg; for (int i = 0; i < data.size(); ++i) { @@ -406,12 +465,12 @@ void ShowImPlotDemoWindow(bool* p_open) { } } ImGui::PopPlotStyleVar(2); - range = ImGui::GetPlotRange(); + range = ImGui::GetPlotLimits(); query = ImGui::GetPlotQuery(); ImGui::EndPlot(); } - ImGui::Text("The current plot range is: [%g,%g,%g,%g]", range.XMin, range.XMax, range.YMin, range.YMax); - ImGui::Text("The current query range is: [%g,%g,%g,%g]", query.XMin, query.XMax, query.YMin, query.YMax); + 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")) { @@ -425,24 +484,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::SetNextPlotRange(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; - ImPlotRange 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::SetNextPlotRange(query.XMin, query.XMax, query.YMin, query.YMax, 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); @@ -450,12 +508,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]; @@ -500,7 +555,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::SetNextPlotRangeX(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]) { @@ -518,6 +573,7 @@ void ShowImPlotDemoWindow(bool* p_open) { } ImGui::EndDragDropTarget(); } + ImGui::Text("Test"); } if (ImGui::CollapsingHeader("Digital and Analog Signals")) { @@ -604,8 +660,8 @@ void ShowImPlotDemoWindow(bool* p_open) { if (showAnalog[i]) dataAnalog[i].AddPoint(t, sin(2*t) - cos(2*t)); } - ImGui::SetNextPlotRangeY(-1, 1); - ImGui::SetNextPlotRangeX(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]) { @@ -653,7 +709,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::SetNextPlotRange(-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}; @@ -688,7 +744,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); - SetNextPlotRange(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) { @@ -699,6 +755,7 @@ void ShowImPlotDemoWindow(bool* p_open) { } ImGui::EndPlot(); } + ImGui::Text("Test"); } //------------------------------------------------------------------------- ImGui::End(); From b9ce343e98d901d75d6e4d57ce3b3529df37a669 Mon Sep 17 00:00:00 2001 From: ozlb Date: Mon, 11 May 2020 14:30:57 +0200 Subject: [PATCH 05/11] QueryX ImGuiMouseCursor_ResizeEW --- implot.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/implot.cpp b/implot.cpp index b457616..546250d 100644 --- a/implot.cpp +++ b/implot.cpp @@ -1007,15 +1007,11 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons plot.DraggingQueryX[i] = false; } if (plot.DraggingQueryX[i]) { - ImGui::SetMouseCursor(ImGuiMouseCursor_ResizeEW); plot.QueryRectX[i].Min += IO.MouseDelta; plot.QueryRectX[i].Max += IO.MouseDelta; - //x limits - //if (plot.QueryRectX[i].Min.x < gp.BB_Grid.Min.x) plot.QueryRectX[i].Min.x = gp.BB_Grid.Min.x; - //if (plot.QueryRectX[i].Max.x > (gp.BB_Grid.Max.x - 10)) plot.QueryRectX[i].Max.x = gp.BB_Grid.Max.x - 10; } if (gp.Hov_Frame && hov_queryX[i] && !plot.DraggingQueryX[i] && !plot.Selecting && !plot.DraggingQuery && !hov_legend) { - ImGui::SetMouseCursor(ImGuiMouseCursor_ResizeEW); + SetMouseCursor(ImGuiMouseCursor_ResizeEW); if (IO.MouseDown[0] && !plot.XAxis.Dragging && !(plot.YAxis[0].Dragging || plot.YAxis[1].Dragging || plot.YAxis[2].Dragging)) { //allow only one cursor dragging per time if (i==0) @@ -1067,7 +1063,7 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons } // Set the mouse cursor based on which axes are moving. int direction = 0; - if (!x.lock && plot.XAxis.Dragging) { + if ((!x.lock && plot.XAxis.Dragging) || any_queryX_dragging) { direction |= (1 << 1); } for (int i = 0; i < MAX_Y_AXES; i++) { From 53ea6a8cd4986d88c2d1ce00f2e95040b28113a1 Mon Sep 17 00:00:00 2001 From: ozlb Date: Mon, 11 May 2020 15:57:36 +0200 Subject: [PATCH 06/11] QueryX removed for PR merge --- implot.cpp | 125 +++++------------------------------------------------ 1 file changed, 11 insertions(+), 114 deletions(-) diff --git a/implot.cpp b/implot.cpp index b3e6328..7154024 100644 --- a/implot.cpp +++ b/implot.cpp @@ -41,6 +41,10 @@ You can read releases logs https://github.com/epezent/implot/releases for more d */ +#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS) +#define _CRT_SECURE_NO_WARNINGS +#endif + #ifdef _MSC_VER #pragma warning (disable: 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen #endif @@ -91,7 +95,6 @@ ImPlotStyle::ImPlotStyle() { Colors[ImPlotCol_YAxis3] = IM_COL_AUTO; Colors[ImPlotCol_Selection] = ImVec4(1,1,0,1); Colors[ImPlotCol_Query] = ImVec4(0,1,0,1); - Colors[ImPlotCol_QueryX] = ImVec4(1,0,0,1); } ImPlotRange::ImPlotRange() : Min(NAN), Max(NAN) {} @@ -278,7 +281,6 @@ struct ImPlot { Selecting = Querying = Queried = DraggingQuery = false; SelectStart = QueryStart = ImVec2(0,0); Flags = PreviousFlags = ImPlotFlags_Default; - DraggingQueryX[0] = DraggingQueryX[1] = false; ColorIdx = 0; CurrentYAxis = 0; } @@ -293,14 +295,9 @@ struct ImPlot { ImRect QueryRect; // relative to BB_grid!! bool DraggingQuery; - bool DraggingQueryX[2]; - ImRect QueryRectX[2]; // relative to BB_grid!! - ImPlotLimits QueryRangeX; - ImPlotAxis XAxis; ImPlotAxis YAxis[MAX_Y_AXES]; - ImPlotFlags Flags, PreviousFlags; int ColorIdx; int CurrentYAxis; @@ -342,8 +339,7 @@ struct ImPlotContext { ImU32 Col_Frame, Col_Bg, Col_Border, Col_Txt, Col_TxtDis, Col_SlctBg, Col_SlctBd, - Col_QryBg, Col_QryBd, - Col_QryX; + Col_QryBg, Col_QryBd; struct AxisColor { AxisColor() : Major(), Minor(), Txt() {} ImU32 Major, Minor, Txt; @@ -847,8 +843,6 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons gp.Col_QryBg = GetColorU32(gp.Style.Colors[ImPlotCol_Query] * ImVec4(1,1,1,0.25f)); gp.Col_QryBd = GetColorU32(gp.Style.Colors[ImPlotCol_Query]); - gp.Col_QryX = GetColorU32(gp.Style.Colors[ImPlotCol_QueryX]); - // BB AND HOVER ----------------------------------------------------------- // frame @@ -911,8 +905,8 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons YPadCalculator y_axis_pad(y, max_label_width, txt_off); const float pad_left = y_axis_pad(0) + (y_label ? txt_height + txt_off : 0); const float pad_right = y_axis_pad(1) + y_axis_pad(2); - gp.BB_Grid = ImRect(gp.BB_Canvas.Min + ImVec2(pad_left, pad_top), gp.BB_Canvas.Max - ImVec2(pad_right, pad_bot)); - gp.Hov_Grid = gp.BB_Grid.Contains(IO.MousePos); + gp.BB_Grid = ImRect(gp.BB_Canvas.Min + ImVec2(pad_left, pad_top), gp.BB_Canvas.Max - ImVec2(pad_right, pad_bot)); + gp.Hov_Grid = gp.BB_Grid.Contains(IO.MousePos); // axis region bbs 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)); @@ -978,50 +972,6 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons } } - //QUERY X - bool hov_queryX[2]; - for (size_t i = 0; i < 2; i++) - { - hov_queryX[i] = plot.QueryRectX[i].Contains(IO.MousePos); - //x limits - bool xAtMax = false; - if (plot.QueryRectX[i].Min.x <= gp.BB_Grid.Min.x) { - plot.QueryRectX[i].Min.x = gp.BB_Grid.Min.x; - } - if (plot.QueryRectX[i].Max.x >= (gp.BB_Grid.Max.x)) { - plot.QueryRectX[i].Max.x = gp.BB_Grid.Max.x; - xAtMax = true; - } - //min cursor "line" width - if ((plot.QueryRectX[i].Max.x - plot.QueryRectX[i].Min.x) < 3) { - if (xAtMax) - plot.QueryRectX[i].Min.x = plot.QueryRectX[i].Max.x - 3; - else - plot.QueryRectX[i].Max.x = plot.QueryRectX[i].Min.x + 3; - } - //y locked to min max grid - plot.QueryRectX[i].Min.y = gp.BB_Grid.Min.y; - plot.QueryRectX[i].Max.y = gp.BB_Grid.Max.y; - // CURSOR1 DRAG ------------------------------------------------------------- - if (plot.DraggingQueryX[i] && (IO.MouseReleased[0] || !IO.MouseDown[0])) { - plot.DraggingQueryX[i] = false; - } - if (plot.DraggingQueryX[i]) { - plot.QueryRectX[i].Min += IO.MouseDelta; - plot.QueryRectX[i].Max += IO.MouseDelta; - } - if (gp.Hov_Frame && hov_queryX[i] && !plot.DraggingQueryX[i] && !plot.Selecting && !plot.DraggingQuery && !hov_legend) { - SetMouseCursor(ImGuiMouseCursor_ResizeEW); - if (IO.MouseDown[0] && !plot.XAxis.Dragging && !(plot.YAxis[0].Dragging || plot.YAxis[1].Dragging || plot.YAxis[2].Dragging)) { - //allow only one cursor dragging per time - if (i==0) - plot.DraggingQueryX[i] = !plot.DraggingQueryX[1]; - else - plot.DraggingQueryX[i] = !plot.DraggingQueryX[0]; - } - } - } - // DRAG INPUT ------------------------------------------------------------- @@ -1037,8 +987,7 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons } } const bool any_y_dragging = plot.YAxis[0].Dragging || plot.YAxis[1].Dragging || plot.YAxis[2].Dragging; - const bool any_queryX_dragging = plot.DraggingQueryX[0] || plot.DraggingQueryX[1]; - bool drag_in_progress = plot.XAxis.Dragging || any_y_dragging || any_queryX_dragging; + bool drag_in_progress = plot.XAxis.Dragging || any_y_dragging; // do drag if (drag_in_progress) { UpdateTransformCache(); @@ -1063,7 +1012,7 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons } // Set the mouse cursor based on which axes are moving. int direction = 0; - if ((!x.lock && plot.XAxis.Dragging) || any_queryX_dragging) { + if (!x.lock && plot.XAxis.Dragging) { direction |= (1 << 1); } for (int i = 0; i < MAX_Y_AXES; i++) { @@ -1286,7 +1235,7 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons if (xt.RenderLabel && xt.PixelPos >= gp.BB_Grid.Min.x - 1 && xt.PixelPos <= gp.BB_Grid.Max.x + 1) DrawList.AddText({xt.PixelPos - xt.Size.x * 0.5f, gp.BB_Grid.Max.y + txt_off}, gp.Col_X.Txt, gp.XTickLabels.Buf.Data + xt.TextOffset); } - ImGui::PopClipRect(); + PopClipRect(); } if (x_label) { const ImVec2 xLabel_size = CalcTextSize(x_label); @@ -1310,7 +1259,7 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons } } } - ImGui::PopClipRect(); + PopClipRect(); if (y_label) { const ImVec2 yLabel_size = CalcTextSizeVertical(y_label); const ImVec2 yLabel_pos(gp.BB_Canvas.Min.x, gp.BB_Grid.GetCenter().y + yLabel_size.y * 0.5f); @@ -1505,8 +1454,6 @@ void EndPlot() { // FINAL RENDER ----------------------------------------------------------- - PushClipRect(gp.BB_Grid.Min, gp.BB_Frame.Max, true); - // render ticks PushPlotClipRect(); if (HasFlag(plot.XAxis.Flags, ImAxisFlags_TickMarks)) { @@ -1587,45 +1534,6 @@ void EndPlot() { DrawList.AddRect( bb_query.Min, bb_query.Max, gp.Col_QryBd); } - //render query x-axis - if (HasFlag(plot.Flags, ImPlotFlags_QueryX)) { - //render x1 - const int lineOffset = -1; - ImVec2 p1, p2; - p1.x = plot.QueryRectX[0].Min.x; - p1.y = plot.QueryRectX[0].Min.y; - p2 = p1 + ImVec2(3,10); - DrawList.AddRectFilled(p1, p2, gp.Col_QryX);//upper rectangle - p1.x = plot.QueryRectX[0].Min.x; - p1.y = plot.QueryRectX[0].Max.y; - p2 = p1 + ImVec2(3,-10); - DrawList.AddRectFilled(p1, p2, gp.Col_QryX);//lower rectangle - p1.x = plot.QueryRectX[0].Min.x; - p1.y = plot.QueryRectX[0].Min.y; - p1 += ImVec2(1, 10 -lineOffset); - p2.x = plot.QueryRectX[0].Min.x; - p2.y = plot.QueryRectX[0].Max.y; - p2 += ImVec2(1, -10 +lineOffset); - DrawList.AddLine(p1, p2, gp.Col_QryX);//line - - //render x2 - p1.x = plot.QueryRectX[1].Min.x; - p1.y = plot.QueryRectX[1].Min.y; - p2 = p1 + ImVec2(3,10); - DrawList.AddRectFilled(p1, p2, gp.Col_QryX);//upper rectangle - p1.x = plot.QueryRectX[1].Min.x; - p1.y = plot.QueryRectX[1].Max.y; - p2 = p1 + ImVec2(3,-10); - DrawList.AddRectFilled(p1, p2, gp.Col_QryX);//lower rectangle - p1.x = plot.QueryRectX[1].Min.x; - p1.y = plot.QueryRectX[1].Min.y; - p1 += ImVec2(1, 10 -lineOffset); - p2.x = plot.QueryRectX[1].Min.x; - p2.y = plot.QueryRectX[1].Max.y; - p2 += ImVec2(1, -10 +lineOffset); - DrawList.AddLine(p1, p2, gp.Col_QryX);//line - } - // render legend const float txt_ht = GetTextLineHeight(); const ImVec2 legend_offset(10, 10); @@ -1865,17 +1773,6 @@ ImPlotLimits GetPlotQuery(int y_axis_in) { return result; } -ImPlotLimits GetPlotQueryX() { - IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "GetPlotQueryX() Needs to be called between BeginPlot() and EndPlot()!"); - ImPlot& plot = *gp.CurrentPlot; - ImVec2 x1 = plot.QueryRectX[0].Min; - ImVec2 x2 = plot.QueryRectX[1].Min; - x1.x += 1; - x2.x += 1; - plot.QueryRangeX.X.Min = PixelsToPlot(x1).x; - plot.QueryRangeX.X.Max = PixelsToPlot(x2).x; - return plot.QueryRangeX; -} //----------------------------------------------------------------------------- // STYLING //----------------------------------------------------------------------------- From 9bfd3902a1687702f5fa2717b720e6566ddaba6d Mon Sep 17 00:00:00 2001 From: ozlb Date: Mon, 11 May 2020 15:58:12 +0200 Subject: [PATCH 07/11] QueryX removed for PR merge --- implot.h | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/implot.h b/implot.h index d2f9b11..d4b791e 100644 --- a/implot.h +++ b/implot.h @@ -49,7 +49,6 @@ enum ImPlotFlags_ { 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_QueryX = 1 << 12,// show x-axis query ImPlotFlags_Default = ImPlotFlags_MousePos | ImPlotFlags_Legend | ImPlotFlags_Highlight | ImPlotFlags_Selection | ImPlotFlags_ContextMenu | ImPlotFlags_CullData }; @@ -84,7 +83,6 @@ enum ImPlotCol_ { 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_QueryX, // x-axis query color (defaults to red) ImPlotCol_COUNT }; @@ -212,8 +210,7 @@ ImPlotLimits GetPlotLimits(int y_axis = -1); bool IsPlotQueried(); /// Returns the current or most recent plot query bounds. ImPlotLimits GetPlotQuery(int y_axis = -1); -/// Returns the current x-axis query range. -ImPlotLimits GetPlotQueryX(); + //----------------------------------------------------------------------------- // Plot Styling //----------------------------------------------------------------------------- From 435440c7da24e7b211c3e4ac0d5b51b58304bdc6 Mon Sep 17 00:00:00 2001 From: ozlb Date: Mon, 11 May 2020 16:00:05 +0200 Subject: [PATCH 08/11] QueryX removed for PR merge --- implot_demo.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/implot_demo.cpp b/implot_demo.cpp index 611d046..84fa447 100644 --- a/implot_demo.cpp +++ b/implot_demo.cpp @@ -755,7 +755,6 @@ void ShowImPlotDemoWindow(bool* p_open) { } ImGui::EndPlot(); } - ImGui::Text("Test"); } //------------------------------------------------------------------------- ImGui::End(); From 2be5451140d43e3ee3c53eb8d75a43be41a34bf5 Mon Sep 17 00:00:00 2001 From: ozlb Date: Tue, 12 May 2020 11:19:04 +0200 Subject: [PATCH 09/11] namespace ImPlot --- implot.cpp | 251 ++++++++++++++++++++++++++++------------------------- 1 file changed, 132 insertions(+), 119 deletions(-) diff --git a/implot.cpp b/implot.cpp index 7154024..98cb7e8 100644 --- a/implot.cpp +++ b/implot.cpp @@ -31,6 +31,12 @@ Below is a change-log of API breaking changes only. If you are using one of the 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/11 (0.2) - ImPlotFlags_Selection was changed to ImPlotFlags_BoxSelect +- 2020/05/11 (0.2) - The namespace ImGui:: was replaced with ImPlot::. As a result, the following additional changes were made: + - Functions that were prefixed or decorated with the word "Plot" have been truncated. E.g., `ImGui::PlotBar` is now just `ImPlot::Bar`. + It should be fairly obvious what was what. + - Some functions have been given names that would have otherwise collided with the ImGui namespace. This has been done to maintain a consistent + style with ImGui. E.g., 'ImGui::PushPlotStyleVar` is now 'ImPlot::PushStyleVar'. - 2020/05/10 (0.2) - The following function/struct names were changes: - ImPlotRange -> ImPlotLimits - GetPlotRange() -> GetPlotLimits() @@ -113,7 +119,11 @@ bool ImPlotLimits::Contains(const ImVec2& p) const { return X.Contains(p.x) && Y.Contains(p.y); } -namespace ImGui { +ImVec2 ImPlotLimits::Size() const { + return ImVec2(X.Size(),Y.Size()); +} + +namespace ImPlot { namespace { @@ -210,7 +220,7 @@ inline void AddTextVertical(ImDrawList *DrawList, const char *text, ImVec2 pos, /// Calculates the size of vertical text inline ImVec2 CalcTextSizeVertical(const char *text) { - ImVec2 sz = CalcTextSize(text); + ImVec2 sz = ImGui::CalcTextSize(text); return ImVec2(sz.y, sz.x); } @@ -276,8 +286,8 @@ struct ImPlotAxis { }; /// Holds Plot state information that must persist between frames -struct ImPlot { - ImPlot() { +struct ImPlotState { + ImPlotState() { Selecting = Querying = Queried = DraggingQuery = false; SelectStart = QueryStart = ImVec2(0,0); Flags = PreviousFlags = ImPlotFlags_Default; @@ -318,13 +328,13 @@ struct ImPlotContext { ImPlotContext() : RenderX(), RenderY() { CurrentPlot = NULL; FitThisFrame = FitX = false; - RestorePlotPalette(); + RestorePalette(); } /// ALl Plots - ImPool Plots; + ImPool Plots; /// Current Plot - ImPlot* CurrentPlot; + ImPlotState* CurrentPlot; // Legend ImVector LegendIndices; ImGuiTextBuffer LegendLabels; @@ -611,7 +621,7 @@ inline void LabelTicks(ImVector &ticks, bool scientific, ImGuiTextBuffer else sprintf(temp, "%g", tk.PlotPos); buffer.append(temp, temp + strlen(temp) + 1); - tk.Size = CalcTextSize(buffer.Buf.Data + tk.TextOffset); + tk.Size = ImGui::CalcTextSize(buffer.Buf.Data + tk.TextOffset); } } } @@ -654,9 +664,9 @@ struct AxisState { void UpdateAxisColor(int axis_flag, ImPlotContext::AxisColor* col) { 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 = GetColorU32(col_Axis); - col->Minor = GetColorU32(col_Axis * ImVec4(1, 1, 1, 0.25f)); - col->Txt = GetColorU32({col_Axis.x, col_Axis.y, col_Axis.z, 1}); + col->Major = ImGui::GetColorU32(col_Axis); + col->Minor = ImGui::GetColorU32(col_Axis * ImVec4(1, 1, 1, 0.25f)); + col->Txt = ImGui::GetColorU32({col_Axis.x, col_Axis.y, col_Axis.z, 1}); } ImRect GetAxisScale(int y_axis, float tx, float ty, float zoom_rate) { @@ -671,7 +681,7 @@ class YPadCalculator { : AxisStates(axis_states), MaxLabelWidths(max_label_widths), TxtOff(txt_off) {} float operator()(int y_axis) { - ImPlot& plot = *gp.CurrentPlot; + ImPlotState& plot = *gp.CurrentPlot; 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. @@ -712,11 +722,11 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons const ImGuiID ID = Window->GetID(title); const ImGuiStyle &Style = G.Style; - const ImGuiIO & IO = GetIO(); + const ImGuiIO & IO = ImGui::GetIO(); bool just_created = gp.Plots.GetByKey(ID) == NULL; gp.CurrentPlot = gp.Plots.GetOrAddByKey(ID); - ImPlot &plot = *gp.CurrentPlot; + ImPlotState &plot = *gp.CurrentPlot; plot.CurrentYAxis = 0; @@ -827,37 +837,37 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons // COLORS ----------------------------------------------------------------- - gp.Col_Frame = gp.Style.Colors[ImPlotCol_FrameBg].w == -1 ? GetColorU32(ImGuiCol_FrameBg) : GetColorU32(gp.Style.Colors[ImPlotCol_FrameBg]); - gp.Col_Bg = gp.Style.Colors[ImPlotCol_PlotBg].w == -1 ? GetColorU32(ImGuiCol_WindowBg) : GetColorU32(gp.Style.Colors[ImPlotCol_PlotBg]); - gp.Col_Border = gp.Style.Colors[ImPlotCol_PlotBorder].w == -1 ? GetColorU32(ImGuiCol_Text, 0.5f) : GetColorU32(gp.Style.Colors[ImPlotCol_PlotBorder]); + gp.Col_Frame = gp.Style.Colors[ImPlotCol_FrameBg].w == -1 ? ImGui::GetColorU32(ImGuiCol_FrameBg) : ImGui::GetColorU32(gp.Style.Colors[ImPlotCol_FrameBg]); + gp.Col_Bg = gp.Style.Colors[ImPlotCol_PlotBg].w == -1 ? ImGui::GetColorU32(ImGuiCol_WindowBg) : ImGui::GetColorU32(gp.Style.Colors[ImPlotCol_PlotBg]); + gp.Col_Border = gp.Style.Colors[ImPlotCol_PlotBorder].w == -1 ? ImGui::GetColorU32(ImGuiCol_Text, 0.5f) : ImGui::GetColorU32(gp.Style.Colors[ImPlotCol_PlotBorder]); UpdateAxisColor(ImPlotCol_XAxis, &gp.Col_X); UpdateAxisColor(ImPlotCol_YAxis, &gp.Col_Y[0]); 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); - gp.Col_SlctBg = GetColorU32(gp.Style.Colors[ImPlotCol_Selection] * ImVec4(1,1,1,0.25f)); - gp.Col_SlctBd = GetColorU32(gp.Style.Colors[ImPlotCol_Selection]); - gp.Col_QryBg = GetColorU32(gp.Style.Colors[ImPlotCol_Query] * ImVec4(1,1,1,0.25f)); - gp.Col_QryBd = GetColorU32(gp.Style.Colors[ImPlotCol_Query]); + gp.Col_Txt = ImGui::GetColorU32(ImGuiCol_Text); + gp.Col_TxtDis = ImGui::GetColorU32(ImGuiCol_TextDisabled); + gp.Col_SlctBg = ImGui::GetColorU32(gp.Style.Colors[ImPlotCol_Selection] * ImVec4(1,1,1,0.25f)); + gp.Col_SlctBd = ImGui::GetColorU32(gp.Style.Colors[ImPlotCol_Selection]); + gp.Col_QryBg = ImGui::GetColorU32(gp.Style.Colors[ImPlotCol_Query] * ImVec4(1,1,1,0.25f)); + gp.Col_QryBd = ImGui::GetColorU32(gp.Style.Colors[ImPlotCol_Query]); // BB AND HOVER ----------------------------------------------------------- // frame - const ImVec2 frame_size = CalcItemSize(size, 100, 100); + const ImVec2 frame_size = ImGui::CalcItemSize(size, 100, 100); gp.BB_Frame = ImRect(Window->DC.CursorPos, Window->DC.CursorPos + frame_size); - ItemSize(gp.BB_Frame); - if (!ItemAdd(gp.BB_Frame, 0, &gp.BB_Frame)) { + ImGui::ItemSize(gp.BB_Frame); + if (!ImGui::ItemAdd(gp.BB_Frame, 0, &gp.BB_Frame)) { gp.NextPlotData = ImNextPlotData(); gp.CurrentPlot = NULL; if (!HasFlag(plot.Flags, ImPlotFlags_NoChild)) ImGui::EndChild(); return false; } - gp.Hov_Frame = ItemHoverable(gp.BB_Frame, ID); - RenderFrame(gp.BB_Frame.Min, gp.BB_Frame.Max, gp.Col_Frame, true, Style.FrameRounding); + gp.Hov_Frame = ImGui::ItemHoverable(gp.BB_Frame, ID); + ImGui::RenderFrame(gp.BB_Frame.Min, gp.BB_Frame.Max, gp.Col_Frame, true, Style.FrameRounding); // canvas bb gp.BB_Canvas = ImRect(gp.BB_Frame.Min + Style.WindowPadding, gp.BB_Frame.Max - Style.WindowPadding); @@ -897,9 +907,9 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons } // grid bb - const ImVec2 title_size = CalcTextSize(title, NULL, true); + const ImVec2 title_size = ImGui::CalcTextSize(title, NULL, true); const float txt_off = 5; - const float txt_height = GetTextLineHeight(); + const float txt_height = ImGui::GetTextLineHeight(); const float pad_top = title_size.x > 0.0f ? txt_height + txt_off : 0; const float pad_bot = (HasFlag(plot.XAxis.Flags, ImAxisFlags_TickLabels) ? txt_height + txt_off : 0) + (x_label ? txt_height + txt_off : 0); YPadCalculator y_axis_pad(y, max_label_width, txt_off); @@ -960,12 +970,12 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons plot.DraggingQuery = false; } if (plot.DraggingQuery) { - SetMouseCursor(ImGuiMouseCursor_ResizeAll); + ImGui::SetMouseCursor(ImGuiMouseCursor_ResizeAll); plot.QueryRect.Min += IO.MouseDelta; plot.QueryRect.Max += IO.MouseDelta; } if (gp.Hov_Frame && gp.Hov_Grid && hov_query && !plot.DraggingQuery && !plot.Selecting && !hov_legend) { - SetMouseCursor(ImGuiMouseCursor_ResizeAll); + ImGui::SetMouseCursor(ImGuiMouseCursor_ResizeAll); 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; @@ -1084,7 +1094,7 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons if (plot.Selecting && (IO.MouseReleased[1] || !IO.MouseDown[1])) { UpdateTransformCache(); ImVec2 select_size = plot.SelectStart - IO.MousePos; - if (HasFlag(plot.Flags, ImPlotFlags_Selection) && ImFabs(select_size.x) > 2 && ImFabs(select_size.y) > 2) { + if (HasFlag(plot.Flags, ImPlotFlags_BoxSelect) && ImFabs(select_size.x) > 2 && ImFabs(select_size.y) > 2) { ImVec2 p1 = PixelsToPlot(plot.SelectStart); ImVec2 p2 = PixelsToPlot(IO.MousePos); if (!x.lock_min && !IO.KeyAlt) @@ -1103,7 +1113,7 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons plot.Selecting = false; } // bad selection - if (plot.Selecting && (!HasFlag(plot.Flags, ImPlotFlags_Selection) || lock_plot) && ImLengthSqr(plot.SelectStart - IO.MousePos) > 4) { + if (plot.Selecting && (!HasFlag(plot.Flags, ImPlotFlags_BoxSelect) || lock_plot) && ImLengthSqr(plot.SelectStart - IO.MousePos) > 4) { ImGui::SetMouseCursor(ImGuiMouseCursor_NotAllowed); } // cancel selection @@ -1151,7 +1161,7 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons plot.Queried = true; plot.QueryStart = plot.SelectStart; } - if (HasFlag(plot.Flags, ImPlotFlags_Selection) && plot.Querying && !IO.KeyCtrl && !IO.MouseDown[2]) { + if (HasFlag(plot.Flags, ImPlotFlags_BoxSelect) && plot.Querying && !IO.KeyCtrl && !IO.MouseDown[2]) { plot.Selecting = true; plot.Querying = false; plot.Queried = false; @@ -1179,7 +1189,7 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons // focus window if ((IO.MouseClicked[0] || IO.MouseClicked[1]) && gp.Hov_Frame) - FocusWindow(GetCurrentWindow()); + ImGui::FocusWindow(ImGui::GetCurrentWindow()); UpdateTransformCache(); @@ -1225,25 +1235,25 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons // render title if (title_size.x > 0.0f) { - RenderText(ImVec2(gp.BB_Canvas.GetCenter().x - title_size.x * 0.5f, gp.BB_Canvas.Min.y), title, NULL, true); + ImGui::RenderText(ImVec2(gp.BB_Canvas.GetCenter().x - title_size.x * 0.5f, gp.BB_Canvas.Min.y), title, NULL, true); } // render labels if (HasFlag(plot.XAxis.Flags, ImAxisFlags_TickLabels)) { - PushClipRect(gp.BB_Frame.Min, gp.BB_Frame.Max, true); + ImGui::PushClipRect(gp.BB_Frame.Min, gp.BB_Frame.Max, true); for (ImTick &xt : gp.XTicks) { if (xt.RenderLabel && xt.PixelPos >= gp.BB_Grid.Min.x - 1 && xt.PixelPos <= gp.BB_Grid.Max.x + 1) DrawList.AddText({xt.PixelPos - xt.Size.x * 0.5f, gp.BB_Grid.Max.y + txt_off}, gp.Col_X.Txt, gp.XTickLabels.Buf.Data + xt.TextOffset); } - PopClipRect(); + ImGui::PopClipRect(); } if (x_label) { - const ImVec2 xLabel_size = CalcTextSize(x_label); + const ImVec2 xLabel_size = ImGui::CalcTextSize(x_label); const ImVec2 xLabel_pos(gp.BB_Grid.GetCenter().x - xLabel_size.x * 0.5f, gp.BB_Canvas.Max.y - txt_height); DrawList.AddText(xLabel_pos, gp.Col_X.Txt, x_label); } - PushClipRect(gp.BB_Frame.Min, gp.BB_Frame.Max, true); + ImGui::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 float x_start = @@ -1259,7 +1269,7 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons } } } - PopClipRect(); + ImGui::PopClipRect(); if (y_label) { const ImVec2 yLabel_size = CalcTextSizeVertical(y_label); const ImVec2 yLabel_pos(gp.BB_Canvas.Min.x, gp.BB_Grid.GetCenter().y + yLabel_size.y * 0.5f); @@ -1269,7 +1279,7 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons // PREP ------------------------------------------------------------------- // push plot ID into stack - PushID(ID); + ImGui::PushID(ID); // reset items count gp.VisibleItemCount = 0; // reset extents @@ -1337,11 +1347,11 @@ inline void AxisMenu(ImPlotAxis& Axis) { FlipFlag(Axis.Flags, ImAxisFlags_TickLabels); } -void PlotContextMenu(ImPlot& plot) { +void PlotContextMenu(ImPlotState& plot) { if (ImGui::BeginMenu("X-Axis")) { - PushID("X"); + ImGui::PushID("X"); AxisMenu(plot.XAxis); - PopID(); + ImGui::PopID(); ImGui::EndMenu(); } for (int i = 0; i < MAX_Y_AXES; i++) { @@ -1358,17 +1368,20 @@ void PlotContextMenu(ImPlot& plot) { snprintf(buf, sizeof(buf) - 1, "Y-Axis %d", i + 1); } if (ImGui::BeginMenu(buf)) { - PushID(i); + ImGui::PushID(i); AxisMenu(plot.YAxis[i]); - PopID(); + ImGui::PopID(); ImGui::EndMenu(); } } ImGui::Separator(); if ((ImGui::BeginMenu("Settings"))) { - if (ImGui::MenuItem("Box Select",NULL,HasFlag(plot.Flags, ImPlotFlags_Selection))) { - FlipFlag(plot.Flags, ImPlotFlags_Selection); + if (ImGui::MenuItem("Box Select",NULL,HasFlag(plot.Flags, ImPlotFlags_BoxSelect))) { + FlipFlag(plot.Flags, ImPlotFlags_BoxSelect); + } + if (ImGui::MenuItem("Query",NULL,HasFlag(plot.Flags, ImPlotFlags_Query))) { + FlipFlag(plot.Flags, ImPlotFlags_Query); } if (ImGui::MenuItem("Crosshairs",NULL,HasFlag(plot.Flags, ImPlotFlags_Crosshairs))) { FlipFlag(plot.Flags, ImPlotFlags_Crosshairs); @@ -1432,11 +1445,11 @@ void EndPlot() { IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "Mismatched BeginPlot()/EndPlot()!"); - ImPlot &plot = *gp.CurrentPlot; + ImPlotState &plot = *gp.CurrentPlot; ImGuiContext &G = *GImGui; ImGuiWindow * Window = G.CurrentWindow; ImDrawList & DrawList = *Window->DrawList; - const ImGuiIO & IO = GetIO(); + const ImGuiIO & IO = ImGui::GetIO(); // AXIS STATES ------------------------------------------------------------ @@ -1462,7 +1475,7 @@ void EndPlot() { } PopPlotClipRect(); - PushClipRect(gp.BB_Grid.Min, {gp.BB_Frame.Max.x, gp.BB_Grid.Max.y}, true); + ImGui::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; } @@ -1492,13 +1505,13 @@ void EndPlot() { } } - PopClipRect(); + ImGui::PopClipRect(); PushPlotClipRect(); // render selection/query if (plot.Selecting) { ImRect select_bb(ImMin(IO.MousePos, plot.SelectStart), ImMax(IO.MousePos, plot.SelectStart)); - if (plot.Selecting && !lock_plot && HasFlag(plot.Flags, ImPlotFlags_Selection)) { + if (plot.Selecting && !lock_plot && HasFlag(plot.Flags, ImPlotFlags_BoxSelect)) { if (IO.KeyAlt && IO.KeyShift && select_bb.GetWidth() > 2 && select_bb.GetHeight() > 2) { DrawList.AddRectFilled(gp.BB_Grid.Min, gp.BB_Grid.Max, gp.Col_SlctBg); DrawList.AddRect( gp.BB_Grid.Min, gp.BB_Grid.Max, gp.Col_SlctBd); @@ -1535,7 +1548,7 @@ void EndPlot() { } // render legend - const float txt_ht = GetTextLineHeight(); + const float txt_ht = ImGui::GetTextLineHeight(); const ImVec2 legend_offset(10, 10); const ImVec2 legend_padding(5, 5); const float legend_icon_size = txt_ht; @@ -1547,14 +1560,14 @@ void EndPlot() { float max_label_width = 0; for (int i = 0; i < nItems; ++i) { const char* label = GetLegendLabel(i); - ImVec2 labelWidth = CalcTextSize(label, NULL, true); + ImVec2 labelWidth = ImGui::CalcTextSize(label, NULL, true); max_label_width = labelWidth.x > max_label_width ? labelWidth.x : max_label_width; } legend_content_bb = ImRect(gp.BB_Grid.Min + legend_offset, gp.BB_Grid.Min + legend_offset + ImVec2(max_label_width, nItems * txt_ht)); plot.BB_Legend = ImRect(legend_content_bb.Min, legend_content_bb.Max + legend_padding * 2 + ImVec2(legend_icon_size, 0)); hov_legend = HasFlag(plot.Flags, ImPlotFlags_Legend) ? gp.Hov_Frame && plot.BB_Legend.Contains(IO.MousePos) : false; // render legend box - DrawList.AddRectFilled(plot.BB_Legend.Min, plot.BB_Legend.Max, GetColorU32(ImGuiCol_PopupBg)); + DrawList.AddRectFilled(plot.BB_Legend.Min, plot.BB_Legend.Max, ImGui::GetColorU32(ImGuiCol_PopupBg)); DrawList.AddRect(plot.BB_Legend.Min, plot.BB_Legend.Max, gp.Col_Border); // render each legend item for (int i = 0; i < nItems; ++i) { @@ -1568,7 +1581,7 @@ void EndPlot() { ImU32 col_hl_txt; if (HasFlag(plot.Flags, ImPlotFlags_Highlight) && hov_legend && (icon_bb.Contains(IO.MousePos) || label_bb.Contains(IO.MousePos))) { item->Highlight = true; - col_hl_txt = GetColorU32(ImLerp(G.Style.Colors[ImGuiCol_Text], item->Color, 0.25f)); + col_hl_txt = ImGui::GetColorU32(ImLerp(G.Style.Colors[ImGuiCol_Text], item->Color, 0.25f)); } else item->Highlight = false; @@ -1576,16 +1589,16 @@ void EndPlot() { if (hov_legend && icon_bb.Contains(IO.MousePos)) { ImVec4 colAlpha = item->Color; colAlpha.w = 0.5f; - iconColor = item->Show ? GetColorU32(colAlpha) - : GetColorU32(ImGuiCol_TextDisabled, 0.5f); + iconColor = item->Show ? ImGui::GetColorU32(colAlpha) + : ImGui::GetColorU32(ImGuiCol_TextDisabled, 0.5f); if (IO.MouseClicked[0]) item->Show = !item->Show; } else { - iconColor = item->Show ? GetColorU32(item->Color) : gp.Col_TxtDis; + iconColor = item->Show ? ImGui::GetColorU32(item->Color) : gp.Col_TxtDis; } DrawList.AddRectFilled(icon_bb.Min, icon_bb.Max, iconColor, 1); const char* label = GetLegendLabel(i); - const char* text_display_end = FindRenderedTextEnd(label, NULL); + const char* text_display_end = ImGui::FindRenderedTextEnd(label, NULL); if (label != text_display_end) DrawList.AddText(legend_content_bb.Min + legend_padding + ImVec2(legend_icon_size, i * txt_ht), item->Show ? (item->Highlight ? col_hl_txt : gp.Col_Txt) : gp.Col_TxtDis, label, text_display_end); @@ -1623,7 +1636,7 @@ void EndPlot() { if (HasFlag(plot.Flags, ImPlotFlags_YAxis3)) { writer.Write(",(%.2f)", gp.LastMousePos[2].y); } - ImVec2 size = CalcTextSize(buffer); + ImVec2 size = ImGui::CalcTextSize(buffer); ImVec2 pos = gp.BB_Grid.Max - size - ImVec2(5, 5); DrawList.AddText(pos, gp.Col_Txt, buffer); } @@ -1668,8 +1681,8 @@ void EndPlot() { gp.CurrentPlot = NULL; // Reset next plot data gp.NextPlotData = ImNextPlotData(); - // Pop PushID at the end of BeginPlot - PopID(); + // Pop ImGui::PushID at the end of BeginPlot + ImGui::PopID(); // End child window if (!HasFlag(plot.Flags, ImPlotFlags_NoChild)) ImGui::EndChild(); @@ -1719,11 +1732,11 @@ ImVec2 GetPlotSize() { void PushPlotClipRect() { IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "PushPlotClipRect() Needs to be called between BeginPlot() and EndPlot()!"); - PushClipRect(gp.BB_Grid.Min, gp.BB_Grid.Max, true); + ImGui::PushClipRect(gp.BB_Grid.Min, gp.BB_Grid.Max, true); } void PopPlotClipRect() { - PopClipRect(); + ImGui::PopClipRect(); } bool IsPlotHovered() { @@ -1743,7 +1756,7 @@ ImPlotLimits GetPlotLimits(int y_axis_in) { 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; + ImPlotState& plot = *gp.CurrentPlot; ImPlotLimits limits; limits.X = plot.XAxis.Range; limits.Y = plot.YAxis[y_axis].Range; @@ -1758,7 +1771,7 @@ bool IsPlotQueried() { 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; + ImPlotState& plot = *gp.CurrentPlot; const int y_axis = y_axis_in >= 0 ? y_axis_in : gp.CurrentPlot->CurrentYAxis; UpdateTransformCache(); @@ -1803,11 +1816,11 @@ static const ImPlotStyleVarInfo* GetPlotStyleVarInfo(ImPlotStyleVar idx) return &GPlotStyleVarInfo[idx]; } -ImPlotStyle& GetPlotStyle() { +ImPlotStyle& GetStyle() { return gp.Style; } -void SetPlotPalette(const ImVec4* colors, int num_colors) { +void SetPalette(const ImVec4* colors, int num_colors) { gp.ColorMap.shrink(0); gp.ColorMap.reserve(num_colors); for (int i = 0; i < num_colors; ++i) { @@ -1816,7 +1829,7 @@ void SetPlotPalette(const ImVec4* colors, int num_colors) { } /// Returns the next unused default plot color -void RestorePlotPalette() { +void RestorePalette() { static ImVec4 default_colors[10] = { {(0.0F), (0.7490196228F), (1.0F), (1.0F)}, // Blues::DeepSkyBlue, {(1.0F), (0.0F), (0.0F), (1.0F)}, // Reds::Red, @@ -1829,18 +1842,18 @@ void RestorePlotPalette() { {(0.5f), (0.5f), (0.5f), (1.0F)}, // Grays::Gray50, {(0.8235294223F), (0.7058823705F), (0.5490196347F), (1.0F)} // Browns::Tan }; - SetPlotPalette(default_colors, 10); + SetPalette(default_colors, 10); } -void PushPlotColor(ImPlotCol idx, ImU32 col) { +void PushStyleColor(ImPlotCol idx, ImU32 col) { ImGuiColorMod backup; backup.Col = idx; backup.BackupValue = gp.Style.Colors[idx]; gp.ColorModifiers.push_back(backup); - gp.Style.Colors[idx] = ColorConvertU32ToFloat4(col); + gp.Style.Colors[idx] = ImGui::ColorConvertU32ToFloat4(col); } -void PushPlotColor(ImPlotCol idx, const ImVec4& col) { +void PushStyleColor(ImPlotCol idx, const ImVec4& col) { ImGuiColorMod backup; backup.Col = idx; backup.BackupValue = gp.Style.Colors[idx]; @@ -1848,7 +1861,7 @@ void PushPlotColor(ImPlotCol idx, const ImVec4& col) { gp.Style.Colors[idx] = col; } -void PopPlotColor(int count) { +void PopStyleColor(int count) { while (count > 0) { ImGuiColorMod& backup = gp.ColorModifiers.back(); @@ -1858,7 +1871,7 @@ void PopPlotColor(int count) { } } -void PushPlotStyleVar(ImPlotStyleVar idx, float val) { +void PushStyleVar(ImPlotStyleVar idx, float val) { const ImPlotStyleVarInfo* var_info = GetPlotStyleVarInfo(idx); if (var_info->Type == ImGuiDataType_Float && var_info->Count == 1) { float* pvar = (float*)var_info->GetVarPtr(&gp.Style); @@ -1866,10 +1879,10 @@ void PushPlotStyleVar(ImPlotStyleVar idx, float val) { *pvar = val; return; } - IM_ASSERT(0 && "Called PushPlotStyleVar() float variant but variable is not a float!"); + IM_ASSERT(0 && "Called PushStyleVar() float variant but variable is not a float!"); } -void PushPlotStyleVar(ImPlotStyleVar idx, int val) { +void PushStyleVar(ImPlotStyleVar idx, int val) { const ImPlotStyleVarInfo* var_info = GetPlotStyleVarInfo(idx); if (var_info->Type == ImGuiDataType_S32 && var_info->Count == 1) { int* pvar = (int*)var_info->GetVarPtr(&gp.Style); @@ -1883,10 +1896,10 @@ void PushPlotStyleVar(ImPlotStyleVar idx, int val) { *pvar = (float)val; return; } - IM_ASSERT(0 && "Called PushPlotStyleVar() int variant but variable is not a int!"); + IM_ASSERT(0 && "Called PushStyleVar() int variant but variable is not a int!"); } -void PopPlotStyleVar(int count) { +void PopStyleVar(int count) { while (count > 0) { ImGuiStyleMod& backup = gp.StyleModifiers.back(); const ImPlotStyleVarInfo* info = GetPlotStyleVarInfo(backup.VarIdx); @@ -2158,7 +2171,7 @@ inline void PlotEx(const char* label_id, Getter getter, int count, int offset) { IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "Plot() Needs to be called between BeginPlot() and EndPlot()!"); - ImPlot* plot = gp.CurrentPlot; + ImPlotState* plot = gp.CurrentPlot; const int y_axis = plot->CurrentYAxis; ImPlotItem* item = RegisterItem(label_id); if (!item->Show) @@ -2170,9 +2183,9 @@ inline void PlotEx(const char* label_id, Getter getter, int count, int offset) const bool rend_mk_line = gp.Style.Colors[ImPlotCol_MarkerOutline].w != 0 && gp.Style.MarkerWeight > 0; const bool rend_mk_fill = gp.Style.Colors[ImPlotCol_MarkerFill].w != 0; - ImU32 col_line = gp.Style.Colors[ImPlotCol_Line].w == -1 ? GetColorU32(item->Color) : GetColorU32(gp.Style.Colors[ImPlotCol_Line]); - ImU32 col_mk_line = gp.Style.Colors[ImPlotCol_MarkerOutline].w == -1 ? col_line : GetColorU32(gp.Style.Colors[ImPlotCol_MarkerOutline]); - ImU32 col_mk_fill = gp.Style.Colors[ImPlotCol_MarkerFill].w == -1 ? col_line : GetColorU32(gp.Style.Colors[ImPlotCol_MarkerFill]); + ImU32 col_line = gp.Style.Colors[ImPlotCol_Line].w == -1 ? ImGui::GetColorU32(item->Color) : ImGui::GetColorU32(gp.Style.Colors[ImPlotCol_Line]); + ImU32 col_mk_line = gp.Style.Colors[ImPlotCol_MarkerOutline].w == -1 ? col_line : ImGui::GetColorU32(gp.Style.Colors[ImPlotCol_MarkerOutline]); + ImU32 col_mk_fill = gp.Style.Colors[ImPlotCol_MarkerFill].w == -1 ? col_line : ImGui::GetColorU32(gp.Style.Colors[ImPlotCol_MarkerFill]); const float line_weight = item->Highlight ? gp.Style.LineWeight * 2 : gp.Style.LineWeight; @@ -2253,19 +2266,19 @@ struct GetterBarH { template void PlotBarEx(const char* label_id, Getter getter, int count, float width, int offset) { - IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "PlotBar() Needs to be called between BeginPlot() and EndPlot()!"); + IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "Bar() Needs to be called between BeginPlot() and EndPlot()!"); ImPlotItem* item = RegisterItem(label_id); if (!item->Show) return; - ImDrawList & DrawList = *GetWindowDrawList(); + ImDrawList & DrawList = *ImGui::GetWindowDrawList(); bool rend_line = gp.Style.Colors[ImPlotCol_Line].w != 0 && gp.Style.LineWeight > 0; bool rend_fill = gp.Style.Colors[ImPlotCol_Fill].w != 0; - ImU32 col_line = gp.Style.Colors[ImPlotCol_Line].w == -1 ? GetColorU32(item->Color) : GetColorU32(gp.Style.Colors[ImPlotCol_Line]); - ImU32 col_fill = gp.Style.Colors[ImPlotCol_Fill].w == -1 ? col_line : GetColorU32(gp.Style.Colors[ImPlotCol_Fill]); + ImU32 col_line = gp.Style.Colors[ImPlotCol_Line].w == -1 ? ImGui::GetColorU32(item->Color) : ImGui::GetColorU32(gp.Style.Colors[ImPlotCol_Line]); + ImU32 col_fill = gp.Style.Colors[ImPlotCol_Fill].w == -1 ? col_line : ImGui::GetColorU32(gp.Style.Colors[ImPlotCol_Fill]); if (rend_fill && col_line == col_fill) rend_line = false; @@ -2303,17 +2316,17 @@ void PlotBarEx(const char* label_id, Getter getter, int count, float width, int PopPlotClipRect(); } -void PlotBar(const char* label_id, const float* values, int count, float width, float shift, int offset, int stride) { +void Bar(const char* label_id, const float* values, int count, float width, float shift, int offset, int stride) { GetterBarV getter(values,shift,stride); PlotBarEx(label_id, getter, count, width, offset); } -void PlotBar(const char* label_id, const float* xs, const float* ys, int count, float width, int offset, int stride) { +void Bar(const char* label_id, const float* xs, const float* ys, int count, float width, int offset, int stride) { Getter2D getter(xs,ys,stride); PlotBarEx(label_id, getter, count, width, offset); } -void PlotBar(const char* label_id, ImVec2 (*getter_func)(void* data, int idx), void* data, int count, float width, int offset) { +void Bar(const char* label_id, ImVec2 (*getter_func)(void* data, int idx), void* data, int count, float width, int offset) { GetterFuncPtrImVec2 getter(getter_func, data); PlotBarEx(label_id, getter, count, width, offset); } @@ -2323,19 +2336,19 @@ void PlotBar(const char* label_id, ImVec2 (*getter_func)(void* data, int idx), v template void PlotBarHEx(const char* label_id, Getter getter, int count, float height, int offset) { - IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "PlotBarH() Needs to be called between BeginPlot() and EndPlot()!"); + IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "BarH() Needs to be called between BeginPlot() and EndPlot()!"); ImPlotItem* item = RegisterItem(label_id); if (!item->Show) return; - ImDrawList & DrawList = *GetWindowDrawList(); + ImDrawList & DrawList = *ImGui::GetWindowDrawList(); bool rend_line = gp.Style.Colors[ImPlotCol_Line].w != 0 && gp.Style.LineWeight > 0; bool rend_fill = gp.Style.Colors[ImPlotCol_Fill].w != 0; - ImU32 col_line = gp.Style.Colors[ImPlotCol_Line].w == -1 ? GetColorU32(item->Color) : GetColorU32(gp.Style.Colors[ImPlotCol_Line]); - ImU32 col_fill = gp.Style.Colors[ImPlotCol_Fill].w == -1 ? col_line : GetColorU32(gp.Style.Colors[ImPlotCol_Fill]); + ImU32 col_line = gp.Style.Colors[ImPlotCol_Line].w == -1 ? ImGui::GetColorU32(item->Color) : ImGui::GetColorU32(gp.Style.Colors[ImPlotCol_Line]); + ImU32 col_fill = gp.Style.Colors[ImPlotCol_Fill].w == -1 ? col_line : ImGui::GetColorU32(gp.Style.Colors[ImPlotCol_Fill]); if (rend_fill && col_line == col_fill) rend_line = false; @@ -2373,17 +2386,17 @@ void PlotBarHEx(const char* label_id, Getter getter, int count, float height, i PopPlotClipRect(); } -void PlotBarH(const char* label_id, const float* values, int count, float height, float shift, int offset, int stride) { +void BarH(const char* label_id, const float* values, int count, float height, float shift, int offset, int stride) { GetterBarH getter(values,shift,stride); PlotBarHEx(label_id, getter, count, height, offset); } -void PlotBarH(const char* label_id, const float* xs, const float* ys, int count, float height, int offset, int stride) { +void BarH(const char* label_id, const float* xs, const float* ys, int count, float height, int offset, int stride) { Getter2D getter(xs,ys,stride); PlotBarHEx(label_id, getter, count, height, offset); } -void PlotBarH(const char* label_id, ImVec2 (*getter_func)(void* data, int idx), void* data, int count, float height, int offset) { +void BarH(const char* label_id, ImVec2 (*getter_func)(void* data, int idx), void* data, int count, float height, int offset) { GetterFuncPtrImVec2 getter(getter_func, data); PlotBarHEx(label_id, getter, count, height, offset); } @@ -2407,18 +2420,18 @@ struct GetterError { template void PlotErrorBarsEx(const char* label_id, Getter getter, int count, int offset) { - IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "PlotErrorBars() Needs to be called between BeginPlot() and EndPlot()!"); + IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "ErrorBars() Needs to be called between BeginPlot() and EndPlot()!"); - ImGuiID id = GetID(label_id); + ImGuiID id = ImGui::GetID(label_id); ImPlotItem* item = gp.CurrentPlot->Items.GetByKey(id); if (item != NULL && item->Show == false) return; - ImDrawList & DrawList = *GetWindowDrawList(); + ImDrawList & DrawList = *ImGui::GetWindowDrawList(); PushPlotClipRect(); - const ImU32 col = gp.Style.Colors[ImPlotCol_ErrorBar].w == -1 ? GetColorU32(ImGuiCol_Text) : GetColorU32(gp.Style.Colors[ImPlotCol_ErrorBar]); + const ImU32 col = gp.Style.Colors[ImPlotCol_ErrorBar].w == -1 ? ImGui::GetColorU32(ImGuiCol_Text) : ImGui::GetColorU32(gp.Style.Colors[ImPlotCol_ErrorBar]); const bool rend_whisker = gp.Style.ErrorBarSize > 0; const float half_whisker = gp.Style.ErrorBarSize * 0.5f; @@ -2448,17 +2461,17 @@ void PlotErrorBarsEx(const char* label_id, Getter getter, int count, int offset) PopPlotClipRect(); } -void PlotErrorBars(const char* label_id, const float* xs, const float* ys, const float* err, int count, int offset, int stride) { +void ErrorBars(const char* label_id, const float* xs, const float* ys, const float* err, int count, int offset, int stride) { GetterError getter(xs, ys, err, err, stride); PlotErrorBarsEx(label_id, getter, count, offset); } -void PlotErrorBars(const char* label_id, const float* xs, const float* ys, const float* neg, const float* pos, int count, int offset, int stride) { +void ErrorBars(const char* label_id, const float* xs, const float* ys, const float* neg, const float* pos, int count, int offset, int stride) { GetterError getter(xs, ys, neg, pos, stride); PlotErrorBarsEx(label_id, getter, count, offset); } -void PlotErrorBars(const char* label_id, ImVec4 (*getter_func)(void* data, int idx), void* data, int count, int offset) { +void ErrorBars(const char* label_id, ImVec4 (*getter_func)(void* data, int idx), void* data, int count, int offset) { GetterFuncPtrImVec4 getter(getter_func, data); PlotErrorBarsEx(label_id, getter, count, offset); } @@ -2481,9 +2494,9 @@ inline void DrawPieSlice(ImDrawList& DrawList, const ImVec2& center, float radiu } -void PlotPieChart(const char** label_ids, float* values, int count, const ImVec2& center, float radius, bool show_percents, float angle0) { - IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "PlotPieChart() Needs to be called between BeginPlot() and EndPlot()!"); - ImDrawList & DrawList = *GetWindowDrawList(); +void PieChart(const char** label_ids, float* values, int count, const ImVec2& center, float radius, bool show_percents, float angle0) { + IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "PieChart() Needs to be called between BeginPlot() and EndPlot()!"); + ImDrawList & DrawList = *ImGui::GetWindowDrawList(); float sum = 0; for (int i = 0; i < count; ++i) @@ -2496,7 +2509,7 @@ void PlotPieChart(const char** label_ids, float* values, int count, const ImVec2 float a1 = angle0 * 2 * IM_PI / 360.0f; for (int i = 0; i < count; ++i) { ImPlotItem* item = RegisterItem(label_ids[i]); - ImU32 col = GetColorU32(item->Color); + ImU32 col = ImGui::GetColorU32(item->Color); float percent = normalize ? values[i] / sum : values[i]; a1 = a0 + 2 * IM_PI * percent; if (item->Show) { @@ -2510,7 +2523,7 @@ void PlotPieChart(const char** label_ids, float* values, int count, const ImVec2 if (show_percents) { static char buffer[8]; sprintf(buffer, "%.0f%%", percent * 100); - ImVec2 size = CalcTextSize(buffer); + ImVec2 size = ImGui::CalcTextSize(buffer); float angle = a0 + (a1 - a0) * 0.5f; ImVec2 pos = PlotToPixels(center.x + 0.5f * radius * cos(angle), center.y + 0.5f * radius * sin(angle)); DrawList.AddText(pos - size * 0.5f + ImVec2(1,1), IM_COL32(0,0,0,255), buffer); @@ -2522,8 +2535,8 @@ void PlotPieChart(const char** label_ids, float* values, int count, const ImVec2 PopPlotClipRect(); } -void PlotLabel(const char* text, float x, float y, bool vertical, const ImVec2& pixel_offset) { - IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "PlotLabel() Needs to be called between BeginPlot() and EndPlot()!"); +void Text(const char* text, float x, float y, bool vertical, const ImVec2& pixel_offset) { + IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "Text() Needs to be called between BeginPlot() and EndPlot()!"); ImDrawList & DrawList = *ImGui::GetWindowDrawList(); PushPlotClipRect(); ImVec2 pos = PlotToPixels({x,y}) + pixel_offset; @@ -2604,7 +2617,7 @@ inline void PlotDigitalEx(const char* label_id, Getter getter, int count, int of 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.0f : 0.9f; - DrawList.AddRectFilled(pMin, pMax, GetColorU32(colAlpha)); + DrawList.AddRectFilled(pMin, pMax, ImGui::GetColorU32(colAlpha)); } } gp.DigitalPlotItemCnt++; @@ -2614,14 +2627,14 @@ inline void PlotDigitalEx(const char* label_id, Getter getter, int count, int of ImGui::PopClipRect(); } -void PlotDigital(const char* label_id, const float* xs, const float* ys, int count, int offset, int stride) { +void Digital(const char* label_id, const float* xs, const float* ys, int count, int offset, int stride) { Getter2D getter(xs,ys,stride); return PlotDigitalEx(label_id, getter, count, offset); } -void PlotDigital(const char* label_id, ImVec2 (*getter_func)(void* data, int idx), void* data, int count, int offset) { +void Digital(const char* label_id, ImVec2 (*getter_func)(void* data, int idx), void* data, int count, int offset) { GetterFuncPtrImVec2 getter(getter_func,data); return PlotDigitalEx(label_id, getter, count, offset); } -} // namespace ImGui +} // namespace ImPlot From c812d2e79b3bd340187e4eb6e7814df90ae38d64 Mon Sep 17 00:00:00 2001 From: ozlb Date: Tue, 12 May 2020 11:19:34 +0200 Subject: [PATCH 10/11] namespace ImPlot --- implot.h | 57 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 29 insertions(+), 28 deletions(-) diff --git a/implot.h b/implot.h index d4b791e..d6c1121 100644 --- a/implot.h +++ b/implot.h @@ -40,7 +40,7 @@ enum ImPlotFlags_ { ImPlotFlags_MousePos = 1 << 0, // the mouse position, in plot coordinates, will be displayed in the bottom-right 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_BoxSelect = 1 << 3, // the user will be able to box-select with right-mouse 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 @@ -49,7 +49,7 @@ enum ImPlotFlags_ { 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 + ImPlotFlags_Default = ImPlotFlags_MousePos | ImPlotFlags_Legend | ImPlotFlags_Highlight | ImPlotFlags_BoxSelect | ImPlotFlags_ContextMenu | ImPlotFlags_CullData }; // Options for plot axes (X and Y) @@ -127,6 +127,7 @@ struct ImPlotLimits { ImPlotRange X, Y; ImPlotLimits(); bool Contains(const ImVec2& p) const; + ImVec2 Size() const; }; // Plot style structure @@ -147,7 +148,7 @@ struct ImPlotStyle { // Core API //----------------------------------------------------------------------------- -namespace ImGui { +namespace ImPlot { // Starts a 2D plotting context. If this function returns true, EndPlot() must // be called, e.g. "if (BeginPlot(...)) { ... EndPlot(); }"". #title_id must @@ -177,24 +178,24 @@ void Plot(const char* label_id, const float* xs, const float* ys, int count, int void Plot(const char* label_id, const ImVec2* data, int count, int offset = 0); void Plot(const char* label_id, ImVec2 (*getter)(void* data, int idx), void* data, int count, int offset = 0); // Plots vertical bars. -void PlotBar(const char* label_id, const float* values, int count, float width = 0.67f, float shift = 0, int offset = 0, int stride = sizeof(float)); -void PlotBar(const char* label_id, const float* xs, const float* ys, int count, float width, int offset = 0, int stride = sizeof(float)); -void PlotBar(const char* label_id, ImVec2 (*getter)(void* data, int idx), void* data, int count, float width, int offset = 0); +void Bar(const char* label_id, const float* values, int count, float width = 0.67f, float shift = 0, int offset = 0, int stride = sizeof(float)); +void Bar(const char* label_id, const float* xs, const float* ys, int count, float width, int offset = 0, int stride = sizeof(float)); +void Bar(const char* label_id, ImVec2 (*getter)(void* data, int idx), void* data, int count, float width, int offset = 0); // Plots horizontal bars. -void PlotBarH(const char* label_id, const float* values, int count, float height = 0.67f, float shift = 0, int offset = 0, int stride = sizeof(float)); -void PlotBarH(const char* label_id, const float* xs, const float* ys, int count, float height, int offset = 0, int stride = sizeof(float)); -void PlotBarH(const char* label_id, ImVec2 (*getter)(void* data, int idx), void* data, int count, float height, int offset = 0); +void BarH(const char* label_id, const float* values, int count, float height = 0.67f, float shift = 0, int offset = 0, int stride = sizeof(float)); +void BarH(const char* label_id, const float* xs, const float* ys, int count, float height, int offset = 0, int stride = sizeof(float)); +void BarH(const char* label_id, ImVec2 (*getter)(void* data, int idx), void* data, int count, float height, int offset = 0); // Plots vertical error bars. -void PlotErrorBars(const char* label_id, const float* xs, const float* ys, const float* err, int count, int offset = 0, int stride = sizeof(float)); -void PlotErrorBars(const char* label_id, const float* xs, const float* ys, const float* neg, const float* pos, int count, int offset = 0, int stride = sizeof(float)); -void PlotErrorBars(const char* label_id, ImVec4 (*getter)(void* data, int idx), void* data, int count, int offset = 0); +void ErrorBars(const char* label_id, const float* xs, const float* ys, const float* err, int count, int offset = 0, int stride = sizeof(float)); +void ErrorBars(const char* label_id, const float* xs, const float* ys, const float* neg, const float* pos, int count, int offset = 0, int stride = sizeof(float)); +void ErrorBars(const char* label_id, ImVec4 (*getter)(void* data, int idx), void* data, int count, int offset = 0); // Plots a pie chart. If the sum of values > 1, each value will be normalized. Center and radius are in plot coordinates. -void PlotPieChart(const char** label_ids, float* values, int count, const ImVec2& center, float radius, bool show_percents = true, float angle0 = 90); -// Plots a text label at point x,y. -void PlotLabel(const char* text, float x, float y, bool vertical = false, const ImVec2& pixel_offset = ImVec2(0,0)); +void PieChart(const char** label_ids, float* values, int count, const ImVec2& center, float radius, bool show_percents = true, float angle0 = 90); // Plots digital channels. -void PlotDigital(const char* label_id, const float* xs, const float* ys, int count, int offset = 0, int stride = sizeof(float)); -void PlotDigital(const char* label_id, ImVec2 (*getter)(void* data, int idx), void* data, int count, int offset = 0); +void Digital(const char* label_id, const float* xs, const float* ys, int count, int offset = 0, int stride = sizeof(float)); +void Digital(const char* label_id, ImVec2 (*getter)(void* data, int idx), void* data, int count, int offset = 0); +// Plots a text label at point x,y. +void Text(const char* text, float x, float y, bool vertical = false, const ImVec2& pixel_offset = ImVec2(0,0)); //----------------------------------------------------------------------------- // Plot Queries @@ -216,26 +217,26 @@ ImPlotLimits GetPlotQuery(int y_axis = -1); //----------------------------------------------------------------------------- // Provides access to plot style structure for permanant modifications to colors, sizes, etc. -ImPlotStyle& GetPlotStyle(); +ImPlotStyle& GetStyle(); // Sets the color palette to be used for plot items. -void SetPlotPalette(const ImVec4* colors, int num_colors); +void SetPalette(const ImVec4* colors, int num_colors); // Restores the default ImPlot color map. -void RestorePlotPalette(); +void RestorePalette(); // Temporarily modify a plot color. -void PushPlotColor(ImPlotCol idx, ImU32 col); +void PushStyleColor(ImPlotCol idx, ImU32 col); // Temporarily modify a plot color. -void PushPlotColor(ImPlotCol idx, const ImVec4& col); +void PushStyleColor(ImPlotCol idx, const ImVec4& col); // Undo temporary color modification. -void PopPlotColor(int count = 1); +void PopStyleColor(int count = 1); // Temporarily modify a style variable of float type. -void PushPlotStyleVar(ImPlotStyleVar idx, float val); +void PushStyleVar(ImPlotStyleVar idx, float val); // Temporarily modify a style variable of int type. -void PushPlotStyleVar(ImPlotStyleVar idx, int val); +void PushStyleVar(ImPlotStyleVar idx, int val); // Undo temporary style modification. -void PopPlotStyleVar(int count = 1); +void PopStyleVar(int count = 1); //----------------------------------------------------------------------------- // Plot Utils @@ -271,6 +272,6 @@ void PopPlotClipRect(); //----------------------------------------------------------------------------- // Shows the ImPlot demo. Add implot_demo.cpp to your sources! -void ShowImPlotDemoWindow(bool* p_open = NULL); +void ShowDemoWindow(bool* p_open = NULL); -} // namespace ImGui +} // namespace ImPlot From 69021f884db31223a0073affb951a426f2ce8faf Mon Sep 17 00:00:00 2001 From: ozlb Date: Tue, 12 May 2020 11:20:23 +0200 Subject: [PATCH 11/11] namespace ImPlot --- implot_demo.cpp | 462 +++++++++++++++++++++++++----------------------- 1 file changed, 236 insertions(+), 226 deletions(-) diff --git a/implot_demo.cpp b/implot_demo.cpp index 84fa447..62d3504 100644 --- a/implot_demo.cpp +++ b/implot_demo.cpp @@ -22,6 +22,10 @@ // ImPlot v0.2 WIP +#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS) +#define _CRT_SECURE_NO_WARNINGS +#endif + #ifdef _MSC_VER #pragma warning (disable: 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen #endif @@ -86,16 +90,27 @@ struct BenchmarkItem { ImVec4 Col; }; -} +} // private namespace -namespace ImGui { +namespace ImPlot { -void ShowImPlotDemoWindow(bool* p_open) { - - //ImVec2 main_viewport_pos = ImGui::GetMainViewport()->Pos; +void ShowDemoWindow(bool* p_open) { + static bool show_app_metrics = false; + static bool show_app_style_editor = false; + if (show_app_metrics) { ImGui::ShowMetricsWindow(&show_app_metrics); } + if (show_app_style_editor) { ImGui::Begin("Style Editor", &show_app_style_editor); ImGui::ShowStyleEditor(); ImGui::End(); } ImGui::SetNextWindowPos(ImVec2(50, 50), ImGuiCond_FirstUseEver); ImGui::SetNextWindowSize(ImVec2(520, 750), ImGuiCond_FirstUseEver); - ImGui::Begin("ImPlot Demo", p_open); + ImGui::Begin("ImPlot Demo", p_open, ImGuiWindowFlags_MenuBar); + if (ImGui::BeginMenuBar()) { + if (ImGui::BeginMenu("Tools")) { + ImGui::MenuItem("Metrics", NULL, &show_app_metrics); + ImGui::MenuItem("Style Editor (ImGui)", NULL, &show_app_style_editor); + ImGui::EndMenu(); + } + ImGui::EndMenuBar(); + } + //------------------------------------------------------------------------- ImGui::Text("ImPlot says hello. (0.2 WIP)"); if (ImGui::CollapsingHeader("Help")) { ImGui::Text("USER GUIDE:"); @@ -132,12 +147,12 @@ void ShowImPlotDemoWindow(bool* p_open) { xs2[i] = i * 0.1f; ys2[i] = xs2[i] * xs2[i]; } - if (ImGui::BeginPlot("Line Plot", "x", "f(x)", {-1,300})) { - ImGui::Plot("sin(50*x)", xs1, ys1, 1001); - ImGui::PushPlotStyleVar(ImPlotStyleVar_Marker, ImMarker_Circle); - ImGui::Plot("x^2", xs2, ys2, 11); - ImGui::PopPlotStyleVar(); - ImGui::EndPlot(); + if (ImPlot::BeginPlot("Line Plot", "x", "f(x)", {-1,300})) { + ImPlot::Plot("sin(50*x)", xs1, ys1, 1001); + ImPlot::PushStyleVar(ImPlotStyleVar_Marker, ImMarker_Circle); + ImPlot::Plot("x^2", xs2, ys2, 11); + ImPlot::PopStyleVar(); + ImPlot::EndPlot(); } } //------------------------------------------------------------------------- @@ -153,18 +168,18 @@ void ShowImPlotDemoWindow(bool* p_open) { xs2[i] = 0.25f + 0.2f * ((float)rand() / (float)RAND_MAX); ys2[i] = 0.75f + 0.2f * ((float)rand() / (float)RAND_MAX); } - if (ImGui::BeginPlot("Scatter Plot", NULL, NULL, {-1,300})) { - ImGui::PushPlotStyleVar(ImPlotStyleVar_LineWeight, 0); - ImGui::PushPlotStyleVar(ImPlotStyleVar_Marker, ImMarker_Cross); - ImGui::PushPlotStyleVar(ImPlotStyleVar_MarkerSize, 3); - ImGui::Plot("Data 1", xs1, ys1, 100); - ImGui::PopPlotStyleVar(2); - ImGui::PushPlotStyleVar(ImPlotStyleVar_Marker, ImMarker_Circle); - ImGui::PushPlotColor(ImPlotCol_MarkerFill, ImVec4{1,0,0,0.25f}); - ImGui::Plot("Data 2", xs2, ys2, 50); - ImGui::PopPlotColor(); - ImGui::PopPlotStyleVar(2); - ImGui::EndPlot(); + if (ImPlot::BeginPlot("Scatter Plot", NULL, NULL, {-1,300})) { + ImPlot::PushStyleVar(ImPlotStyleVar_LineWeight, 0); + ImPlot::PushStyleVar(ImPlotStyleVar_Marker, ImMarker_Cross); + ImPlot::PushStyleVar(ImPlotStyleVar_MarkerSize, 3); + ImPlot::Plot("Data 1", xs1, ys1, 100); + ImPlot::PopStyleVar(2); + ImPlot::PushStyleVar(ImPlotStyleVar_Marker, ImMarker_Circle); + ImPlot::PushStyleColor(ImPlotCol_MarkerFill, ImVec4{1,0,0,0.25f}); + ImPlot::Plot("Data 2", xs2, ys2, 50); + ImPlot::PopStyleColor(); + ImPlot::PopStyleVar(2); + ImPlot::EndPlot(); } } //------------------------------------------------------------------------- @@ -172,24 +187,24 @@ void ShowImPlotDemoWindow(bool* p_open) { static bool horz = false; ImGui::Checkbox("Horizontal",&horz); if (horz) - ImGui::SetNextPlotLimits(0, 110, -0.5f, 9.5f, ImGuiCond_Always); + ImPlot::SetNextPlotLimits(0, 110, -0.5f, 9.5f, ImGuiCond_Always); else - ImGui::SetNextPlotLimits(-0.5f, 9.5f, 0, 110, ImGuiCond_Always); - if (ImGui::BeginPlot("Bar Plot", horz ? "Score": "Student", horz ? "Student" : "Score", {-1, 300})) { + ImPlot::SetNextPlotLimits(-0.5f, 9.5f, 0, 110, ImGuiCond_Always); + if (ImPlot::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}; static float grade[10] = {80, 69, 52, 92, 72, 78, 75, 76, 89, 95}; if (horz) { - ImGui::PlotBarH("Midterm Exam", midtm, 10, 0.2f, -0.2f); - ImGui::PlotBarH("Final Exam", final, 10, 0.2f, 0); - ImGui::PlotBarH("Course Grade", grade, 10, 0.2f, 0.2f); + ImPlot::BarH("Midterm Exam", midtm, 10, 0.2f, -0.2f); + ImPlot::BarH("Final Exam", final, 10, 0.2f, 0); + ImPlot::BarH("Course Grade", grade, 10, 0.2f, 0.2f); } else { - ImGui::PlotBar("Midterm Exam", midtm, 10, 0.2f, -0.2f); - ImGui::PlotBar("Final Exam", final, 10, 0.2f, 0); - ImGui::PlotBar("Course Grade", grade, 10, 0.2f, 0.2f); + ImPlot::Bar("Midterm Exam", midtm, 10, 0.2f, -0.2f); + ImPlot::Bar("Final Exam", final, 10, 0.2f, 0); + ImPlot::Bar("Course Grade", grade, 10, 0.2f, 0.2f); } - ImGui::EndPlot(); + ImPlot::EndPlot(); } } //------------------------------------------------------------------------- @@ -199,21 +214,21 @@ 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::SetNextPlotLimits(0, 6, 0, 10); - if (ImGui::BeginPlot("##ErrorBars",NULL,NULL,ImVec2(-1,300))) { + ImPlot::SetNextPlotLimits(0, 6, 0, 10); + if (ImPlot::BeginPlot("##ErrorBars",NULL,NULL,ImVec2(-1,300))) { - ImGui::PlotBar("Bar", xs, bar, 5, 0.5f); - ImGui::PlotErrorBars("Bar", xs, bar, err1, 5); + ImPlot::Bar("Bar", xs, bar, 5, 0.5f); + ImPlot::ErrorBars("Bar", xs, bar, err1, 5); - ImGui::PushPlotStyleVar(ImPlotStyleVar_Marker, ImMarker_Circle); - ImGui::PushPlotStyleVar(ImPlotStyleVar_MarkerSize, 3); - ImGui::PushPlotColor(ImPlotCol_ErrorBar, ImVec4(1,0,0,1)); - ImGui::PlotErrorBars("Line", xs, lin, err1, err2, 5); - ImGui::Plot("Line", xs, lin, 5); - ImGui::PopPlotStyleVar(2); - ImGui::PopPlotColor(); + ImPlot::PushStyleVar(ImPlotStyleVar_Marker, ImMarker_Circle); + ImPlot::PushStyleVar(ImPlotStyleVar_MarkerSize, 3); + ImPlot::PushStyleColor(ImPlotCol_ErrorBar, ImVec4(1,0,0,1)); + ImPlot::ErrorBars("Line", xs, lin, err1, err2, 5); + ImPlot::Plot("Line", xs, lin, 5); + ImPlot::PopStyleVar(2); + ImPlot::PopStyleColor(); - ImGui::EndPlot(); + ImPlot::EndPlot(); } } //------------------------------------------------------------------------- @@ -224,9 +239,9 @@ void ShowImPlotDemoWindow(bool* p_open) { float radius = 0.4f; // in plot units, not pixels 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(); + if (ImPlot::BeginPlot("##Pie1", NULL, NULL, ImVec2(250,250), ImPlotFlags_Legend, 0, 0)) { + ImPlot::PieChart(labels1, pre_normalized, 4, center, radius); + ImPlot::EndPlot(); } ImGui::SameLine(); @@ -237,17 +252,16 @@ void ShowImPlotDemoWindow(bool* p_open) { {0.9882f, 0.3059f, 0.1647f, 1.0f}, {0.7412f, 0.0f, 0.1490f, 1.0f}, }; - ImGui::SetPlotPalette(YlOrRd, 5); + ImPlot::SetPalette(YlOrRd, 5); 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)) { - ImGui::PlotPieChart(labels2, not_normalized, 5, center, radius); - ImGui::EndPlot(); + if (ImPlot::BeginPlot("##Pie2", NULL, NULL, ImVec2(250,250), ImPlotFlags_Legend, 0, 0)) { + ImPlot::PieChart(labels2, not_normalized, 5, center, radius); + ImPlot::EndPlot(); } - ImGui::RestorePlotPalette(); + ImPlot::RestorePalette(); } - //------------------------------------------------------------------------- if (ImGui::CollapsingHeader("Realtime Plots")) { ImGui::BulletText("Move your mouse to change the data!"); @@ -264,95 +278,94 @@ void ShowImPlotDemoWindow(bool* p_open) { sdata2.AddPoint(t, mouse.y * 0.0005f); rdata2.AddPoint(t, mouse.y * 0.0005f); } - ImGui::SetNextPlotLimitsX(t - 10, t, paused ? ImGuiCond_Once : ImGuiCond_Always); + ImPlot::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(); + if (ImPlot::BeginPlot("##Scrolling", NULL, NULL, {-1,150}, ImPlotFlags_Default, rt_axis, rt_axis)) { + ImPlot::Plot("Data 1", &sdata1.Data[0].x, &sdata1.Data[0].y, sdata1.Data.size(), sdata1.Offset, 2 * sizeof(float)); + ImPlot::Plot("Data 2", &sdata2.Data[0].x, &sdata2.Data[0].y, sdata2.Data.size(), sdata2.Offset, 2 * sizeof(float)); + ImPlot::EndPlot(); } - 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)); - ImGui::EndPlot(); + ImPlot::SetNextPlotLimitsX(0, 10, ImGuiCond_Always); + if (ImPlot::BeginPlot("##Rolling", NULL, NULL, {-1,150}, ImPlotFlags_Default, rt_axis, rt_axis)) { + ImPlot::Plot("Data 1", &rdata1.Data[0].x, &rdata1.Data[0].y, rdata1.Data.size(), 0, 2 * sizeof(float)); + ImPlot::Plot("Data 2", &rdata2.Data[0].x, &rdata2.Data[0].y, rdata2.Data.size(), 0, 2 * sizeof(float)); + ImPlot::EndPlot(); } } - //------------------------------------------------------------------------- - if (ImGui::CollapsingHeader("Markers and Labels")) { - ImGui::SetNextPlotLimits(0, 10, 0, 12); - if (ImGui::BeginPlot("##MarkerStyles", NULL, NULL, ImVec2(-1,300), 0, 0, 0)) { + if (ImGui::CollapsingHeader("Markers and Text")) { + ImPlot::SetNextPlotLimits(0, 10, 0, 12); + if (ImPlot::BeginPlot("##MarkerStyles", NULL, NULL, ImVec2(-1,300), 0, 0, 0)) { float xs[2] = {1,4}; float ys[2] = {10,11}; // filled - ImGui::PushPlotStyleVar(ImPlotStyleVar_Marker, ImMarker_Circle); - ImGui::Plot("Circle##Fill", xs, ys, 2); - ImGui::PushPlotStyleVar(ImPlotStyleVar_Marker, ImMarker_Square); ys[0]--; ys[1]--; - ImGui::Plot("Square##Fill", xs, ys, 2); - ImGui::PushPlotStyleVar(ImPlotStyleVar_Marker, ImMarker_Diamond); ys[0]--; ys[1]--; - ImGui::Plot("Diamond##Fill", xs, ys, 2); - ImGui::PushPlotStyleVar(ImPlotStyleVar_Marker, ImMarker_Up); ys[0]--; ys[1]--; - ImGui::Plot("Up##Fill", xs, ys, 2); - ImGui::PushPlotStyleVar(ImPlotStyleVar_Marker, ImMarker_Down); ys[0]--; ys[1]--; - ImGui::Plot("Down##Fill", xs, ys, 2); - ImGui::PushPlotStyleVar(ImPlotStyleVar_Marker, ImMarker_Left); ys[0]--; ys[1]--; - ImGui::Plot("Left##Fill", xs, ys, 2); - ImGui::PushPlotStyleVar(ImPlotStyleVar_Marker, ImMarker_Right); ys[0]--; ys[1]--; - ImGui::Plot("Right##Fill", xs, ys, 2); - ImGui::PushPlotStyleVar(ImPlotStyleVar_Marker, ImMarker_Cross); ys[0]--; ys[1]--; - ImGui::Plot("Cross##Fill", xs, ys, 2); - ImGui::PushPlotStyleVar(ImPlotStyleVar_Marker, ImMarker_Plus); ys[0]--; ys[1]--; - ImGui::Plot("Plus##Fill", xs, ys, 2); - ImGui::PushPlotStyleVar(ImPlotStyleVar_Marker, ImMarker_Asterisk); ys[0]--; ys[1]--; - ImGui::Plot("Asterisk##Fill", xs, ys, 2); - ImGui::PopPlotStyleVar(10); + ImPlot::PushStyleVar(ImPlotStyleVar_Marker, ImMarker_Circle); + ImPlot::Plot("Circle##Fill", xs, ys, 2); + ImPlot::PushStyleVar(ImPlotStyleVar_Marker, ImMarker_Square); ys[0]--; ys[1]--; + ImPlot::Plot("Square##Fill", xs, ys, 2); + ImPlot::PushStyleVar(ImPlotStyleVar_Marker, ImMarker_Diamond); ys[0]--; ys[1]--; + ImPlot::Plot("Diamond##Fill", xs, ys, 2); + ImPlot::PushStyleVar(ImPlotStyleVar_Marker, ImMarker_Up); ys[0]--; ys[1]--; + ImPlot::Plot("Up##Fill", xs, ys, 2); + ImPlot::PushStyleVar(ImPlotStyleVar_Marker, ImMarker_Down); ys[0]--; ys[1]--; + ImPlot::Plot("Down##Fill", xs, ys, 2); + ImPlot::PushStyleVar(ImPlotStyleVar_Marker, ImMarker_Left); ys[0]--; ys[1]--; + ImPlot::Plot("Left##Fill", xs, ys, 2); + ImPlot::PushStyleVar(ImPlotStyleVar_Marker, ImMarker_Right); ys[0]--; ys[1]--; + ImPlot::Plot("Right##Fill", xs, ys, 2); + ImPlot::PushStyleVar(ImPlotStyleVar_Marker, ImMarker_Cross); ys[0]--; ys[1]--; + ImPlot::Plot("Cross##Fill", xs, ys, 2); + ImPlot::PushStyleVar(ImPlotStyleVar_Marker, ImMarker_Plus); ys[0]--; ys[1]--; + ImPlot::Plot("Plus##Fill", xs, ys, 2); + ImPlot::PushStyleVar(ImPlotStyleVar_Marker, ImMarker_Asterisk); ys[0]--; ys[1]--; + ImPlot::Plot("Asterisk##Fill", xs, ys, 2); + ImPlot::PopStyleVar(10); xs[0] = 6; xs[1] = 9; ys[0] = 10; ys[1] = 11; - ImGui::PushPlotColor(ImPlotCol_MarkerFill, ImVec4(0,0,0,0)); - ImGui::PushPlotStyleVar(ImPlotStyleVar_Marker, ImMarker_Circle); - ImGui::Plot("Circle", xs, ys, 2); - ImGui::PushPlotStyleVar(ImPlotStyleVar_Marker, ImMarker_Square); ys[0]--; ys[1]--; - ImGui::Plot("Square", xs, ys, 2); - ImGui::PushPlotStyleVar(ImPlotStyleVar_Marker, ImMarker_Diamond); ys[0]--; ys[1]--; - ImGui::Plot("Diamond", xs, ys, 2); - ImGui::PushPlotStyleVar(ImPlotStyleVar_Marker, ImMarker_Up); ys[0]--; ys[1]--; - ImGui::Plot("Up", xs, ys, 2); - ImGui::PushPlotStyleVar(ImPlotStyleVar_Marker, ImMarker_Down); ys[0]--; ys[1]--; - ImGui::Plot("Down", xs, ys, 2); - ImGui::PushPlotStyleVar(ImPlotStyleVar_Marker, ImMarker_Left); ys[0]--; ys[1]--; - ImGui::Plot("Left", xs, ys, 2); - ImGui::PushPlotStyleVar(ImPlotStyleVar_Marker, ImMarker_Right); ys[0]--; ys[1]--; - ImGui::Plot("Right", xs, ys, 2); - ImGui::PushPlotStyleVar(ImPlotStyleVar_Marker, ImMarker_Cross); ys[0]--; ys[1]--; - ImGui::Plot("Cross", xs, ys, 2); - ImGui::PushPlotStyleVar(ImPlotStyleVar_Marker, ImMarker_Plus); ys[0]--; ys[1]--; - ImGui::Plot("Plus", xs, ys, 2); - ImGui::PushPlotStyleVar(ImPlotStyleVar_Marker, ImMarker_Asterisk); ys[0]--; ys[1]--; - ImGui::Plot("Asterisk", xs, ys, 2); - ImGui::PopPlotColor(); - ImGui::PopPlotStyleVar(10); + ImPlot::PushStyleColor(ImPlotCol_MarkerFill, ImVec4(0,0,0,0)); + ImPlot::PushStyleVar(ImPlotStyleVar_Marker, ImMarker_Circle); + ImPlot::Plot("Circle", xs, ys, 2); + ImPlot::PushStyleVar(ImPlotStyleVar_Marker, ImMarker_Square); ys[0]--; ys[1]--; + ImPlot::Plot("Square", xs, ys, 2); + ImPlot::PushStyleVar(ImPlotStyleVar_Marker, ImMarker_Diamond); ys[0]--; ys[1]--; + ImPlot::Plot("Diamond", xs, ys, 2); + ImPlot::PushStyleVar(ImPlotStyleVar_Marker, ImMarker_Up); ys[0]--; ys[1]--; + ImPlot::Plot("Up", xs, ys, 2); + ImPlot::PushStyleVar(ImPlotStyleVar_Marker, ImMarker_Down); ys[0]--; ys[1]--; + ImPlot::Plot("Down", xs, ys, 2); + ImPlot::PushStyleVar(ImPlotStyleVar_Marker, ImMarker_Left); ys[0]--; ys[1]--; + ImPlot::Plot("Left", xs, ys, 2); + ImPlot::PushStyleVar(ImPlotStyleVar_Marker, ImMarker_Right); ys[0]--; ys[1]--; + ImPlot::Plot("Right", xs, ys, 2); + ImPlot::PushStyleVar(ImPlotStyleVar_Marker, ImMarker_Cross); ys[0]--; ys[1]--; + ImPlot::Plot("Cross", xs, ys, 2); + ImPlot::PushStyleVar(ImPlotStyleVar_Marker, ImMarker_Plus); ys[0]--; ys[1]--; + ImPlot::Plot("Plus", xs, ys, 2); + ImPlot::PushStyleVar(ImPlotStyleVar_Marker, ImMarker_Asterisk); ys[0]--; ys[1]--; + ImPlot::Plot("Asterisk", xs, ys, 2); + ImPlot::PopStyleColor(); + ImPlot::PopStyleVar(10); xs[0] = 5; xs[1] = 5; ys[0] = 1; ys[1] = 11; - ImGui::PushPlotStyleVar(ImPlotStyleVar_LineWeight, 2); - ImGui::PushPlotStyleVar(ImPlotStyleVar_MarkerSize, 8); - ImGui::PushPlotStyleVar(ImPlotStyleVar_MarkerWeight, 2); - ImGui::PushPlotStyleVar(ImPlotStyleVar_Marker, ImMarker_Circle | ImMarker_Cross); - ImGui::PushPlotColor(ImPlotCol_MarkerOutline, ImVec4(0,0,0,1)); - ImGui::PushPlotColor(ImPlotCol_MarkerFill, ImVec4(1,1,1,1)); - ImGui::PushPlotColor(ImPlotCol_Line, ImVec4(0,0,0,1)); - ImGui::Plot("Circle|Cross", xs, ys, 2); - ImGui::PopPlotStyleVar(4); - ImGui::PopPlotColor(3); + ImPlot::PushStyleVar(ImPlotStyleVar_LineWeight, 2); + ImPlot::PushStyleVar(ImPlotStyleVar_MarkerSize, 8); + ImPlot::PushStyleVar(ImPlotStyleVar_MarkerWeight, 2); + ImPlot::PushStyleVar(ImPlotStyleVar_Marker, ImMarker_Circle | ImMarker_Cross); + ImPlot::PushStyleColor(ImPlotCol_MarkerOutline, ImVec4(0,0,0,1)); + ImPlot::PushStyleColor(ImPlotCol_MarkerFill, ImVec4(1,1,1,1)); + ImPlot::PushStyleColor(ImPlotCol_Line, ImVec4(0,0,0,1)); + ImPlot::Plot("Circle|Cross", xs, ys, 2); + ImPlot::PopStyleVar(4); + ImPlot::PopStyleColor(3); - ImGui::PlotLabel("Filled Markers", 1.5, 11.75); - ImGui::PlotLabel("Open Markers", 6.75, 11.75); - ImGui::PlotLabel("Fancy Markers", 4.5, 4.25, true); + ImPlot::Text("Filled Markers", 1.5, 11.75); + ImPlot::Text("Open Markers", 6.75, 11.75); + ImPlot::Text("Fancy Markers", 4.5, 4.25, true); - ImGui::EndPlot(); + ImPlot::EndPlot(); } } //------------------------------------------------------------------------- @@ -365,13 +378,13 @@ void ShowImPlotDemoWindow(bool* p_open) { ys2[i] = log(xs[i]); ys3[i] = pow(10.0f, xs[i]); } - 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); - ImGui::Plot("f(x) = log(x)", xs, ys2, 1001); - ImGui::Plot("f(x) = 10^x", xs, ys3, 21); - ImGui::EndPlot(); + ImPlot::SetNextPlotLimits(0.1f, 100, 0, 10); + if (ImPlot::BeginPlot("Log Plot", NULL, NULL, ImVec2(-1,300), ImPlotFlags_Default, ImAxisFlags_Default | ImAxisFlags_LogScale )) { + ImPlot::Plot("f(x) = x", xs, xs, 1001); + ImPlot::Plot("f(x) = sin(x)+1", xs, ys1, 1001); + ImPlot::Plot("f(x) = log(x)", xs, ys2, 1001); + ImPlot::Plot("f(x) = 10^x", xs, ys3, 21); + ImPlot::EndPlot(); } } //------------------------------------------------------------------------- @@ -401,33 +414,33 @@ void ShowImPlotDemoWindow(bool* p_open) { ys3[i] = sin(xs[i]+0.5f) * 100 + 200; xs2[i] = xs[i] + 10.0f; } - 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); + ImPlot::SetNextPlotLimits(0.1f, 100, 0, 10); + ImPlot::SetNextPlotLimitsY(0, 1, ImGuiCond_Once, 1); + ImPlot::SetNextPlotLimitsY(0, 300, ImGuiCond_Once, 2); + ImPlot::PushStyleColor(ImPlotCol_YAxis, y1_col); + ImPlot::PushStyleColor(ImPlotCol_YAxis2, y2_col); + ImPlot::PushStyleColor(ImPlotCol_YAxis3, y3_col); - if (ImGui::BeginPlot("Multi-Axis Plot", NULL, NULL, ImVec2(-1,300), + if (ImPlot::BeginPlot("Multi-Axis Plot", NULL, NULL, ImVec2(-1,300), ImPlotFlags_Default | (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); + ImPlot::Plot("f(x) = x", xs, xs, 1001); + ImPlot::Plot("f(x) = sin(x)*3+1", xs, ys1, 1001); if (y2_axis) { - ImGui::SetPlotYAxis(1); - ImGui::Plot("f(x) = cos(x)*.2+.5 (Y2)", xs, ys2, 1001); + ImPlot::SetPlotYAxis(1); + ImPlot::Plot("f(x) = cos(x)*.2+.5 (Y2)", xs, ys2, 1001); } if (y3_axis) { - ImGui::SetPlotYAxis(2); - ImGui::Plot("f(x) = sin(x+.5)*100+200 (Y3)", xs2, ys3, 1001); + ImPlot::SetPlotYAxis(2); + ImPlot::Plot("f(x) = sin(x+.5)*100+200 (Y3)", xs2, ys3, 1001); } - ImGui::EndPlot(); + ImPlot::EndPlot(); } - ImGui::PopPlotColor(3); + ImPlot::PopStyleColor(3); } //------------------------------------------------------------------------- if (ImGui::CollapsingHeader("Querying")) { @@ -440,15 +453,15 @@ void ShowImPlotDemoWindow(bool* p_open) { ImGui::Unindent(); static ImVector data; 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); - ImGui::PushPlotStyleVar(ImPlotStyleVar_Marker, ImMarker_Diamond); + if (ImPlot::BeginPlot("##Drawing", NULL, NULL, ImVec2(-1,300), ImPlotFlags_Default | ImPlotFlags_Query, ImAxisFlags_GridLines, ImAxisFlags_GridLines)) { + if (ImPlot::IsPlotHovered() && ImGui::IsMouseClicked(0) && ImGui::GetIO().KeyCtrl) + data.push_back(ImPlot::GetPlotMousePos()); + ImPlot::PushStyleVar(ImPlotStyleVar_LineWeight, 0); + ImPlot::PushStyleVar(ImPlotStyleVar_Marker, ImMarker_Diamond); 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) { - ImPlotLimits range = ImGui::GetPlotQuery(); + ImPlot::Plot("Points", &data[0].x, &data[0].y, data.size(), 0, 2 * sizeof(float)); + if (ImPlot::IsPlotQueried() && data.size() > 0) { + ImPlotLimits range = ImPlot::GetPlotQuery(); int cnt = 0; ImVec2 avg; for (int i = 0; i < data.size(); ++i) { @@ -461,13 +474,13 @@ void ShowImPlotDemoWindow(bool* p_open) { if (cnt > 0) { avg.x = avg.x / cnt; avg.y = avg.y / cnt; - ImGui::Plot("Average", &avg.x, &avg.y, 1); + ImPlot::Plot("Average", &avg.x, &avg.y, 1); } } - ImGui::PopPlotStyleVar(2); - range = ImGui::GetPlotLimits(); - query = ImGui::GetPlotQuery(); - ImGui::EndPlot(); + ImPlot::PopStyleVar(2); + range = ImPlot::GetPlotLimits(); + query = ImPlot::GetPlotQuery(); + ImPlot::EndPlot(); } 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); @@ -490,22 +503,22 @@ void ShowImPlotDemoWindow(bool* p_open) { 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 (see above for controls)."); - ImGui::SetNextPlotLimits(0,0.01f,-1,1); + ImPlot::SetNextPlotLimits(0,0.01f,-1,1); ImAxisFlags flgs = ImAxisFlags_Default & ~ImAxisFlags_TickLabels; 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(); + if (ImPlot::BeginPlot("##View1",NULL,NULL,ImVec2(-1,150), ImPlotFlags_Default | ImPlotFlags_Query, flgs, flgs)) { + ImPlot::Plot("Signal 1", x_data, y_data1, 512); + ImPlot::Plot("Signal 2", x_data, y_data2, 512); + ImPlot::Plot("Signal 3", x_data, y_data3, 512); + query = ImPlot::GetPlotQuery(); + ImPlot::EndPlot(); } - 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); - ImGui::Plot("Signal 3", x_data, y_data3, 512); - ImGui::EndPlot(); + ImPlot::SetNextPlotLimits(query.X.Min, query.X.Max, query.Y.Min, query.Y.Max, ImGuiCond_Always); + if (ImPlot::BeginPlot("##View2",NULL,NULL,ImVec2(-1,150), 0, 0, 0)) { + ImPlot::Plot("Signal 1", x_data, y_data1, 512); + ImPlot::Plot("Signal 2", x_data, y_data2, 512); + ImPlot::Plot("Signal 3", x_data, y_data3, 512); + ImPlot::EndPlot(); } } //------------------------------------------------------------------------- @@ -555,16 +568,16 @@ 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::SetNextPlotLimitsX(t - 10, t, paused ? ImGuiCond_Once : ImGuiCond_Always); - if (ImGui::BeginPlot("##DND", NULL, NULL, ImVec2(-1,300), ImPlotFlags_Default)) { + ImPlot::SetNextPlotLimitsX(t - 10, t, paused ? ImGuiCond_Once : ImGuiCond_Always); + if (ImPlot::BeginPlot("##DND", NULL, NULL, ImVec2(-1,300), ImPlotFlags_Default)) { for (int i = 0; i < 10; ++i) { if (show[i]) { char label[8]; sprintf(label, "data_%d", i); - ImGui::Plot(label, &data[i].Data[0].x, &data[i].Data[0].y, data[i].Data.size(), data[i].Offset, 2 * sizeof(float)); + ImPlot::Plot(label, &data[i].Data[0].x, &data[i].Data[0].y, data[i].Data.size(), data[i].Offset, 2 * sizeof(float)); } } - ImGui::EndPlot(); + ImPlot::EndPlot(); } if (ImGui::BeginDragDropTarget()) { if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("DND_PLOT")) { @@ -573,12 +586,9 @@ void ShowImPlotDemoWindow(bool* p_open) { } ImGui::EndDragDropTarget(); } - ImGui::Text("Test"); } - + //------------------------------------------------------------------------- if (ImGui::CollapsingHeader("Digital and Analog Signals")) { - - static bool paused = false; #define K_PLOT_DIGITAL_CH_COUNT 4 #define K_PLOT_ANALOG_CH_COUNT 4 @@ -660,17 +670,17 @@ void ShowImPlotDemoWindow(bool* p_open) { if (showAnalog[i]) dataAnalog[i].AddPoint(t, sin(2*t) - cos(2*t)); } - 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)) { + ImPlot::SetNextPlotLimitsY(-1, 1); + ImPlot::SetNextPlotLimitsX(t - 10.0f, t, paused ? ImGuiCond_Once : ImGuiCond_Always); + if (ImPlot::BeginPlot("##Digital", NULL, NULL, ImVec2(-1,300), ImPlotFlags_Default)) { for (int i = 0; i < K_PLOT_DIGITAL_CH_COUNT; ++i) { if (showDigital[i]) { char label[32]; sprintf(label, "digital_%d", i); - ImGui::PushPlotStyleVar(ImPlotStyleVar_DigitalBitHeight, bitHeight); - ImGui::PushPlotStyleVar(ImPlotStyleVar_DigitalBitGap, bitGap); - ImGui::PlotDigital(label, &dataDigital[i].Data[0].x, &dataDigital[i].Data[0].y, dataDigital[i].Data.size(), dataDigital[i].Offset, 2 * sizeof(float)); - ImGui::PopPlotStyleVar(2); + ImPlot::PushStyleVar(ImPlotStyleVar_DigitalBitHeight, bitHeight); + ImPlot::PushStyleVar(ImPlotStyleVar_DigitalBitGap, bitGap); + ImPlot::Digital(label, &dataDigital[i].Data[0].x, &dataDigital[i].Data[0].y, dataDigital[i].Data.size(), dataDigital[i].Offset, 2 * sizeof(float)); + ImPlot::PopStyleVar(2); } } for (int i = 0; i < K_PLOT_ANALOG_CH_COUNT; ++i) { @@ -678,10 +688,10 @@ void ShowImPlotDemoWindow(bool* p_open) { char label[32]; sprintf(label, "analog_%d", i); if (dataAnalog[i].Data.size() > 0) - ImGui::Plot(label, &dataAnalog[i].Data[0].x, &dataAnalog[i].Data[0].y, dataAnalog[i].Data.size(), dataAnalog[i].Offset, 2 * sizeof(float)); + ImPlot::Plot(label, &dataAnalog[i].Data[0].x, &dataAnalog[i].Data[0].y, dataAnalog[i].Data.size(), dataAnalog[i].Offset, 2 * sizeof(float)); } } - ImGui::EndPlot(); + ImPlot::EndPlot(); } if (ImGui::BeginDragDropTarget()) { if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("DND_DIGITAL_PLOT")) { @@ -702,40 +712,41 @@ void ShowImPlotDemoWindow(bool* p_open) { {0.996f, 0.278f, 0.380f, 1.0f}, {(0.1176470593F), (0.5647059083F), (1.0F), (1.0F)}, }; - ImGui::SetPlotPalette(my_palette, 3); - ImGui::PushPlotColor(ImPlotCol_FrameBg, IM_COL32(32,51,77,255)); - ImGui::PushPlotColor(ImPlotCol_PlotBg, {0,0,0,0}); - ImGui::PushPlotColor(ImPlotCol_PlotBorder, {0,0,0,0}); - 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::SetNextPlotLimits(-0.5f, 9.5f, -0.5f, 9.5f); - if (ImGui::BeginPlot("##Custom", NULL, NULL, {-1,300}, ImPlotFlags_Default & ~ImPlotFlags_Legend, 0)) { + ImPlot::SetPalette(my_palette, 3); + ImPlot::PushStyleColor(ImPlotCol_FrameBg, IM_COL32(32,51,77,255)); + ImPlot::PushStyleColor(ImPlotCol_PlotBg, {0,0,0,0}); + ImPlot::PushStyleColor(ImPlotCol_PlotBorder, {0,0,0,0}); + ImPlot::PushStyleColor(ImPlotCol_XAxis, IM_COL32(192, 192, 192, 192)); + ImPlot::PushStyleColor(ImPlotCol_YAxis, IM_COL32(192, 192, 192, 192)); + ImPlot::PushStyleVar(ImPlotStyleVar_LineWeight, 2); + ImPlot::SetNextPlotLimits(-0.5f, 9.5f, -0.5f, 9.5f); + if (ImPlot::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}; float dot[10] = {7,6,6,7,8,5,6,5,8,7}; - ImGui::PlotBar("Bar", bar, 10, 0.5f); - ImGui::Plot("Line", lin, 10); - ImGui::PushPlotStyleVar(ImPlotStyleVar_LineWeight, 0); - ImGui::PushPlotStyleVar(ImPlotStyleVar_Marker, ImMarker_Square); - ImGui::Plot("Dot", dot, 10); - ImGui::PopPlotStyleVar(2); - ImGui::EndPlot(); + ImPlot::Bar("Bar", bar, 10, 0.5f); + ImPlot::Plot("Line", lin, 10); + ImPlot::PushStyleVar(ImPlotStyleVar_LineWeight, 0); + ImPlot::PushStyleVar(ImPlotStyleVar_Marker, ImMarker_Square); + ImPlot::Plot("Dot", dot, 10); + ImPlot::PopStyleVar(2); + ImPlot::EndPlot(); } - ImGui::PopPlotColor(5); - ImGui::PopPlotStyleVar(); - ImGui::RestorePlotPalette(); + ImPlot::PopStyleColor(5); + ImPlot::PopStyleVar(); + ImPlot::RestorePalette(); } + //------------------------------------------------------------------------- if (ImGui::CollapsingHeader("Custom Rendering")) { - if (ImGui::BeginPlot("##CustomRend",NULL,NULL,{-1,300})) { - ImVec2 cntr = ImGui::PlotToPixels({0.5f, 0.5f}); - ImVec2 rmin = ImGui::PlotToPixels({0.25f, 0.75f}); - ImVec2 rmax = ImGui::PlotToPixels({0.75f, 0.25f}); - ImGui::PushPlotClipRect(); + if (ImPlot::BeginPlot("##CustomRend",NULL,NULL,{-1,300})) { + ImVec2 cntr = ImPlot::PlotToPixels({0.5f, 0.5f}); + ImVec2 rmin = ImPlot::PlotToPixels({0.25f, 0.75f}); + ImVec2 rmax = ImPlot::PlotToPixels({0.75f, 0.25f}); + ImPlot::PushPlotClipRect(); ImGui::GetWindowDrawList()->AddCircleFilled(cntr,20,IM_COL32(255,255,0,255),20); ImGui::GetWindowDrawList()->AddRect(rmin, rmax, IM_COL32(128,0,255,255)); - ImGui::PopPlotClipRect(); - ImGui::EndPlot(); + ImPlot::PopPlotClipRect(); + ImPlot::EndPlot(); } } //------------------------------------------------------------------------- @@ -745,20 +756,19 @@ void ShowImPlotDemoWindow(bool* p_open) { ImGui::BulletText("Make sure VSync is disabled."); ImGui::BulletText("%d lines with %d points each @ %.3f FPS.",n_items,1000,ImGui::GetIO().Framerate); SetNextPlotLimits(0,1,0,1, ImGuiCond_Always); - if (ImGui::BeginPlot("##Bench",NULL,NULL,{-1,300},ImPlotFlags_Default | ImPlotFlags_NoChild)) { + if (ImPlot::BeginPlot("##Bench",NULL,NULL,{-1,300},ImPlotFlags_Default | ImPlotFlags_NoChild)) { char buff[16]; for (int i = 0; i < 100; ++i) { sprintf(buff, "item_%d",i); - ImGui::PushPlotColor(ImPlotCol_Line, items[i].Col); - ImGui::Plot(buff, items[i].Data, 1000); - ImGui::PopPlotColor(); + ImPlot::PushStyleColor(ImPlotCol_Line, items[i].Col); + ImPlot::Plot(buff, items[i].Data, 1000); + ImPlot::PopStyleColor(); } - ImGui::EndPlot(); + ImPlot::EndPlot(); } } //------------------------------------------------------------------------- - ImGui::End(); - + ImGui::End(); } -} // namespace ImGui +} // namespace ImPlot