From 43f78f62b91a7ec6f3e7d440d195f1abfe38fbf9 Mon Sep 17 00:00:00 2001 From: Evan Pezent Date: Wed, 3 Jun 2020 22:18:47 -0500 Subject: [PATCH 1/5] add formats to PieChart and Heatmap, fix compiler warnings --- implot.cpp | 54 ++++++++++++++++++++++++++++--------------------- implot.h | 14 ++++++------- implot_demo.cpp | 22 +++++++------------- 3 files changed, 45 insertions(+), 45 deletions(-) diff --git a/implot.cpp b/implot.cpp index bb15520..2b26980 100644 --- a/implot.cpp +++ b/implot.cpp @@ -2862,7 +2862,7 @@ inline void DrawPieSlice(ImDrawList& DrawList, const ImPlotPoint& center, double } template -void PlotPieChartEx(const char** label_ids, T* values, int count, T x, T y, T radius, bool show_percents, T angle0) { +void PlotPieChartEx(const char** label_ids, T* values, int count, T x, T y, T radius, const char* fmt, T angle0) { IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "PlotPieChart() needs to be called between BeginPlot() and EndPlot()!"); ImDrawList & DrawList = *ImGui::GetWindowDrawList(); @@ -2890,9 +2890,9 @@ void PlotPieChartEx(const char** label_ids, T* values, int count, T x, T y, T ra DrawPieSlice(DrawList, center, radius, a0, a0 + (a1 - a0) * 0.5f, col); DrawPieSlice(DrawList, center, radius, a0 + (a1 - a0) * 0.5f, a1, col); } - if (show_percents) { - char buffer[8]; - sprintf(buffer, "%.0f%%", percent * 100); + if (fmt != NULL) { + char buffer[32]; + sprintf(buffer, fmt, percent * 100); ImVec2 size = ImGui::CalcTextSize(buffer); T angle = a0 + (a1 - a0) * 0.5f; ImVec2 pos = PlotToPixels(center.x + 0.5f * radius * cos(angle), center.y + 0.5f * radius * sin(angle)); @@ -2908,15 +2908,15 @@ void PlotPieChartEx(const char** label_ids, T* values, int count, T x, T y, T ra //----------------------------------------------------------------------------- // float -void PlotPieChart(const char** label_ids, float* values, int count, float x, float y, float radius, bool show_percents, float angle0) { - return PlotPieChartEx(label_ids, values, count, x, y, radius, show_percents, angle0); +void PlotPieChart(const char** label_ids, float* values, int count, float x, float y, float radius, const char* fmt, float angle0) { + return PlotPieChartEx(label_ids, values, count, x, y, radius, fmt, angle0); } //----------------------------------------------------------------------------- // double -void PlotPieChart(const char** label_ids, double* values, int count, double x, double y, double radius, bool show_percents, double angle0) { - return PlotPieChartEx(label_ids, values, count, x, y, radius, show_percents, angle0); +void PlotPieChart(const char** label_ids, double* values, int count, double x, double y, double radius, const char* fmt, double angle0) { + return PlotPieChartEx(label_ids, values, count, x, y, radius, fmt, angle0); } //----------------------------------------------------------------------------- @@ -2924,7 +2924,7 @@ void PlotPieChart(const char** label_ids, double* values, int count, double x, d //----------------------------------------------------------------------------- template -void RenderHeatmap(Transformer transformer, ImDrawList& DrawList, const T* values, int rows, int cols, T scale_min, T scale_max, bool show_labels, const ImPlotPoint& bounds_min, const ImPlotPoint& bounds_max) { +void RenderHeatmap(Transformer transformer, ImDrawList& DrawList, const T* values, int rows, int cols, T scale_min, T scale_max, const char* fmt, const ImPlotPoint& bounds_min, const ImPlotPoint& bounds_max) { const double w = (bounds_max.x - bounds_min.x) / cols; const double h = (bounds_max.y - bounds_min.y) / rows; const ImPlotPoint half_size(w*0.5,h*0.5); @@ -2937,7 +2937,6 @@ void RenderHeatmap(Transformer transformer, ImDrawList& DrawList, const T* value ImPlotPoint p; p.x = bounds_min.x + 0.5*w + c*w; p.y = bounds_min.y + 1 - (0.5*h + r*h); - ImVec2 px = transformer(p); ImVec2 a = transformer(p.x - half_size.x, p.y - half_size.y); ImVec2 b = transformer(p.x + half_size.x, p.y + half_size.y); float t = (float)Remap(values[i], scale_min, scale_max, T(0), T(1)); @@ -2947,7 +2946,7 @@ void RenderHeatmap(Transformer transformer, ImDrawList& DrawList, const T* value i++; } } - if (show_labels) { + if (fmt != NULL) { // this has to go in its own loop due to PrimReserve above i = 0; for (int r = 0; r < rows; ++r) { @@ -2957,7 +2956,7 @@ void RenderHeatmap(Transformer transformer, ImDrawList& DrawList, const T* value p.y = bounds_min.y + 1 - (0.5*h + r*h); ImVec2 px = transformer(p); char buff[32]; - sprintf(buff, "%g", values[i]); + sprintf(buff, fmt, values[i]); ImVec2 size = ImGui::CalcTextSize(buff); DrawList.AddText(px - size * 0.5f, ImGui::GetColorU32(ImGuiCol_Text), buff); i++; @@ -2967,7 +2966,7 @@ void RenderHeatmap(Transformer transformer, ImDrawList& DrawList, const T* value } template -void PlotHeatmapEx(const char* label_id, const T* values, int rows, int cols, T scale_min, T scale_max, bool show_labels, const ImPlotPoint& bounds_min, const ImPlotPoint& bounds_max) { +void PlotHeatmapEx(const char* label_id, const T* values, int rows, int cols, T scale_min, T scale_max, const char* fmt, const ImPlotPoint& bounds_min, const ImPlotPoint& bounds_max) { IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "PlotHeatmap() needs to be called between BeginPlot() and EndPlot()!"); IM_ASSERT_USER_ERROR(scale_min != scale_max, "Scale values must be different!"); ImPlotItem* item = RegisterItem(label_id); @@ -2982,28 +2981,28 @@ void PlotHeatmapEx(const char* label_id, const T* values, int rows, int cols, T ImPlotState* plot = gp.CurrentPlot; int y_axis = plot->CurrentYAxis; if (HasFlag(plot->XAxis.Flags, ImPlotAxisFlags_LogScale) && HasFlag(plot->YAxis[y_axis].Flags, ImPlotAxisFlags_LogScale)) - RenderHeatmap(TransformerLogLog(y_axis), DrawList, values, rows, cols, scale_min, scale_max, show_labels, bounds_min, bounds_max); + RenderHeatmap(TransformerLogLog(y_axis), DrawList, values, rows, cols, scale_min, scale_max, fmt, bounds_min, bounds_max); else if (HasFlag(plot->XAxis.Flags, ImPlotAxisFlags_LogScale)) - RenderHeatmap(TransformerLogLin(y_axis), DrawList, values, rows, cols, scale_min, scale_max, show_labels, bounds_min, bounds_max); + RenderHeatmap(TransformerLogLin(y_axis), DrawList, values, rows, cols, scale_min, scale_max, fmt, bounds_min, bounds_max); else if (HasFlag(plot->YAxis[y_axis].Flags, ImPlotAxisFlags_LogScale)) - RenderHeatmap(TransformerLinLog(y_axis), DrawList, values, rows, cols, scale_min, scale_max, show_labels, bounds_min, bounds_max); + RenderHeatmap(TransformerLinLog(y_axis), DrawList, values, rows, cols, scale_min, scale_max, fmt, bounds_min, bounds_max); else - RenderHeatmap(TransformerLinLin(y_axis), DrawList, values, rows, cols, scale_min, scale_max, show_labels, bounds_min, bounds_max); + RenderHeatmap(TransformerLinLin(y_axis), DrawList, values, rows, cols, scale_min, scale_max, fmt, bounds_min, bounds_max); ImGui::PopClipRect(); } //----------------------------------------------------------------------------- // float -void PlotHeatmap(const char* label_id, const float* values, int rows, int cols, float scale_min, float scale_max, bool show_labels, const ImPlotPoint& bounds_min, const ImPlotPoint& bounds_max) { - return PlotHeatmapEx(label_id, values, rows, cols, scale_min, scale_max, show_labels, bounds_min, bounds_max); +void PlotHeatmap(const char* label_id, const float* values, int rows, int cols, float scale_min, float scale_max, const char* fmt, const ImPlotPoint& bounds_min, const ImPlotPoint& bounds_max) { + return PlotHeatmapEx(label_id, values, rows, cols, scale_min, scale_max, fmt, bounds_min, bounds_max); } //----------------------------------------------------------------------------- // double -void PlotHeatmap(const char* label_id, const double* values, int rows, int cols, double scale_min, double scale_max, bool show_labels, const ImPlotPoint& bounds_min, const ImPlotPoint& bounds_max) { - return PlotHeatmapEx(label_id, values, rows, cols, scale_min, scale_max, show_labels, bounds_min, bounds_max); +void PlotHeatmap(const char* label_id, const double* values, int rows, int cols, double scale_min, double scale_max, const char* fmt, const ImPlotPoint& bounds_min, const ImPlotPoint& bounds_max) { + return PlotHeatmapEx(label_id, values, rows, cols, scale_min, scale_max, fmt, bounds_min, bounds_max); } //----------------------------------------------------------------------------- @@ -3201,7 +3200,6 @@ void ShowColormapScale(double scale_min, double scale_max, float height) { int num_cols = GetColormapSize(); float h_step = (height - 2 * Style.WindowPadding.y) / (num_cols - 1); - const ImVec2 uv = DrawList._Data->TexUvWhitePixel; for (int i = 0; i < num_cols-1; ++i) { ImRect rect(bb_grad.Min.x, bb_grad.Min.y + h_step * i, bb_grad.Max.x, bb_grad.Min.y + h_step * (i + 1)); ImU32 col1 = ImGui::GetColorU32(GetColormapColor(num_cols - 1 - i)); @@ -3223,7 +3221,7 @@ void ShowColormapScale(double scale_min, double scale_max, float height) { } -void SetColormap(ImPlotColormap colormap) { +void SetColormap(ImPlotColormap colormap, int samples) { static int csizes[ImPlotColormap_COUNT] = {10,9,9,12,11,11,11,11,11,11}; static OffsetCalculator coffs(csizes); static ImVec4 cdata[] { @@ -3347,6 +3345,16 @@ void SetColormap(ImPlotColormap colormap) { // TODO: Calculate offsets at compile time gp.Colormap = &cdata[coffs.Offsets[colormap]]; gp.ColormapSize = csizes[colormap]; + + if (samples > 1) { + static ImVector resampled; + resampled.resize(samples); + for (int i = 0; i < samples; ++i) { + float t = i * 1.0f / (samples - 1); + resampled[i] = LerpColormap(t); + } + SetColormap(&resampled[0], samples); + } } } // namespace ImPlot diff --git a/implot.h b/implot.h index 8f2ef9a..1970e56 100644 --- a/implot.h +++ b/implot.h @@ -239,12 +239,12 @@ void PlotErrorBars(const char* label_id, const float* xs, const float* ys, const void PlotErrorBars(const char* label_id, const double* xs, const double* ys, const double* neg, const double* pos, int count, int offset = 0, int stride = sizeof(double)); // 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, float x, float y, float radius, bool show_percents = true, float angle0 = 90); -void PlotPieChart(const char** label_ids, double* values, int count, double x, double y, double radius, bool show_percents = true, double angle0 = 90); +void PlotPieChart(const char** label_ids, float* values, int count, float x, float y, float radius, const char* label_fmt = "%.1f%%", float angle0 = 90); +void PlotPieChart(const char** label_ids, double* values, int count, double x, double y, double radius, const char* label_fmt = "%.1f%%", double angle0 = 90); -// Plots a 2D heatmap chart. Values are expected to be in row-major order. -void PlotHeatmap(const char* label_id, const float* values, int rows, int cols, float scale_min, float scale_max, bool show_labels = true, const ImPlotPoint& bounds_min = ImPlotPoint(0,0), const ImPlotPoint& bounds_max = ImPlotPoint(1,1)); -void PlotHeatmap(const char* label_id, const double* values, int rows, int cols, double scale_min, double scale_max, bool show_labels = true, const ImPlotPoint& bounds_min = ImPlotPoint(0,0), const ImPlotPoint& bounds_max = ImPlotPoint(1,1)); +// Plots a 2D heatmap chart. Values are expected to be in row-major order. label_fmt can be set to NULL for no labels. +void PlotHeatmap(const char* label_id, const float* values, int rows, int cols, float scale_min, float scale_max, const char* label_fmt = "%.1f", const ImPlotPoint& bounds_min = ImPlotPoint(0,0), const ImPlotPoint& bounds_max = ImPlotPoint(1,1)); +void PlotHeatmap(const char* label_id, const double* values, int rows, int cols, double scale_min, double scale_max, const char* label_fmt = "%.1f", const ImPlotPoint& bounds_min = ImPlotPoint(0,0), const ImPlotPoint& bounds_max = ImPlotPoint(1,1)); // Plots digital data. void PlotDigital(const char* label_id, const float* xs, const float* ys, int count, int offset = 0, int stride = sizeof(float)); @@ -291,8 +291,8 @@ void PushStyleVar(ImPlotStyleVar idx, int val); // Undo temporary style modification. void PopStyleVar(int count = 1); -// Switch to one of the built-in colormaps. -void SetColormap(ImPlotColormap colormap); +// Switch to one of the built-in colormaps. If samples is greater than 1, the map will be linearly resampled. +void SetColormap(ImPlotColormap colormap, int samples = 0); // Sets a custom colormap. void SetColormap(const ImVec4* colors, int num_colors); // Returns the size of the current colormap diff --git a/implot_demo.cpp b/implot_demo.cpp index a7a0d02..a42de28 100644 --- a/implot_demo.cpp +++ b/implot_demo.cpp @@ -303,20 +303,12 @@ void ShowDemoWindow(bool* p_open) { ImPlot::EndPlot(); } ImGui::SameLine(); - - static ImVec4 YlOrRd[5] = { - ImVec4(1.0000f, 1.0000f, 0.8000f, 1.0f), - ImVec4(0.9961f, 0.8510f, 0.4627f, 1.0f), - ImVec4(0.9961f, 0.6314f, 0.2627f, 1.0f), - ImVec4(0.9882f, 0.3059f, 0.1647f, 1.0f), - ImVec4(0.7412f, 0.0f, 0.1490f, 1.0f), - }; - ImPlot::SetColormap(YlOrRd, 5); + ImPlot::SetColormap(ImPlotColormap_Cool, 5); SetNextPlotLimits(0,1,0,1,ImGuiCond_Always); - static const char* labels2[] = {"One","Two","Three","Four","Five"}; - static t_float not_normalized[] = {1,2,3,4,5}; + static const char* labels2[] = {"One##1","One##2","Two","Three","Five"}; + static t_float not_normalized[] = {1,1,2,3,5}; if (ImPlot::BeginPlot("##Pie2", NULL, NULL, ImVec2(250,250), ImPlotFlags_Legend, 0, 0)) { - ImPlot::PlotPieChart(labels2, not_normalized, 5, 0.5f, 0.5f, 0.4f, false, 0); + ImPlot::PlotPieChart(labels2, not_normalized, 5, 0.5f, 0.5f, 0.4f, NULL, 0); ImPlot::EndPlot(); } ImPlot::SetColormap(ImPlotColormap_Default); @@ -341,7 +333,7 @@ void ShowDemoWindow(bool* p_open) { map = (map + 1) % ImPlotColormap_COUNT; ImPlot::SetColormap(map); ImGui::SameLine(); - ImGui::LabelText("##Colormap Index", cmap_names[map]); + ImGui::LabelText("##Colormap Index", "%s", cmap_names[map]); ImGui::SetNextItemWidth(225); ImGui::DragFloat("Max",&scale_max,0.01f,0.1f,20); static ImPlotAxisFlags axes_flags = ImPlotAxisFlags_LockMin | ImPlotAxisFlags_LockMax | ImPlotAxisFlags_TickLabels; @@ -362,7 +354,7 @@ void ShowDemoWindow(bool* p_open) { static ImVec4 gray[2] = {ImVec4(0,0,0,1), ImVec4(1,1,1,1)}; ImPlot::SetColormap(&gray[0], 2); if (ImPlot::BeginPlot("##Heatmap2",NULL,NULL,ImVec2(225,225),ImPlotFlags_ContextMenu,0,0)) { - ImPlot::PlotHeatmap("heat",values2,100,100,0,1,false); + ImPlot::PlotHeatmap("heat",values2,100,100,0,1,NULL); ImPlot::EndPlot(); } ImPlot::SetColormap(ImPlotColormap_Default); @@ -403,7 +395,7 @@ void ShowDemoWindow(bool* p_open) { if (ImGui::Button("Change Colormap##2")) map = (map + 1) % ImPlotColormap_COUNT; ImGui::SameLine(); - ImGui::LabelText("##Colormap Index", cmap_names[map]); + ImGui::LabelText("##Colormap Index", "%s", cmap_names[map]); ImGui::PushID(map); // NB: This is merely a workaround so that the demo can cycle color maps. You wouldn't need to do this in your own code! ImPlot::SetNextPlotLimits(0, 10, 0, 12); if (ImPlot::BeginPlot("##MarkerStyles", NULL, NULL, ImVec2(-1,0), 0, 0, 0)) { From a70bbe5cff99f7d7948bcc7c56f2b9a302aaa976 Mon Sep 17 00:00:00 2001 From: Evan Pezent Date: Thu, 4 Jun 2020 00:11:43 -0500 Subject: [PATCH 2/5] internal refactors and demo improvements --- implot.cpp | 314 +++++++++++++++++++++++++----------------------- implot_demo.cpp | 39 +++--- 2 files changed, 184 insertions(+), 169 deletions(-) diff --git a/implot.cpp b/implot.cpp index 2b26980..85b66bf 100644 --- a/implot.cpp +++ b/implot.cpp @@ -254,23 +254,7 @@ struct ImPlotTick { bool Labeled; }; -struct ImPlotItem { - ImPlotItem() { - Show = true; - Highlight = false; - Color = NextColor(); - NameOffset = -1; - ID = 0; - } - ~ImPlotItem() { ID = 0; } - bool Show; - bool Highlight; - ImVec4 Color; - int NameOffset; - ImGuiID ID; -}; - -/// Plot axis structure. You shouldn't need to construct this! +/// Axis state information that must persist after EndPlot struct ImPlotAxis { ImPlotAxis() { Dragging = false; @@ -287,7 +271,64 @@ struct ImPlotAxis { ImPlotAxisFlags Flags, PreviousFlags; }; -/// Holds Plot state information that must persist between frames +/// Axis state information only needed between BeginPlot/EndPlot +struct ImPlotAxisState { + ImPlotAxis* axis; + bool has_range; + ImGuiCond range_cond; + bool present; + int present_so_far; + bool invert; + bool lock_min; + bool lock_max; + bool lock; + ImPlotAxisState(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)), + invert(HasFlag(axis->Flags, ImPlotAxisFlags_Invert)), + lock_min(HasFlag(axis->Flags, ImPlotAxisFlags_LockMin) || (has_range && range_cond == ImGuiCond_Always)), + lock_max(HasFlag(axis->Flags, ImPlotAxisFlags_LockMax) || (has_range && range_cond == ImGuiCond_Always)), + lock(!present || ((lock_min && lock_max) || (has_range && range_cond == ImGuiCond_Always))) {} + + ImPlotAxisState() + : axis(), + has_range(), + range_cond(), + present(), + present_so_far(), + invert(), + lock_min(), + lock_max(), + lock() {} +}; + +struct ImPlotAxisColor { + ImPlotAxisColor() : Major(), Minor(), Txt() {} + ImU32 Major, Minor, Txt; +}; + +/// State information for Plot items +struct ImPlotItem { + ImPlotItem() { + Show = true; + Highlight = false; + Color = NextColor(); + NameOffset = -1; + ID = 0; + } + ~ImPlotItem() { ID = 0; } + bool Show; + bool Highlight; + ImVec4 Color; + int NameOffset; + ImGuiID ID; +}; + +/// Holds Plot state information that must persist after EndPlot struct ImPlotState { ImPlotState() { Selecting = Querying = Queried = DraggingQuery = false; @@ -393,12 +434,10 @@ struct ImPlotContext { Col_Txt, Col_TxtDis, Col_SlctBg, Col_SlctBd, Col_QryBg, Col_QryBd; - struct AxisColor { - AxisColor() : Major(), Minor(), Txt() {} - ImU32 Major, Minor, Txt; - }; - AxisColor Col_X; - AxisColor Col_Y[MAX_Y_AXES]; + ImPlotAxisColor Col_X; + ImPlotAxisColor Col_Y[MAX_Y_AXES]; + ImPlotAxisState X; + ImPlotAxisState Y[MAX_Y_AXES]; // Tick marks ImVector XTicks, YTicks[MAX_Y_AXES]; ImGuiTextBuffer XTickLabels, YTickLabels[MAX_Y_AXES]; @@ -720,42 +759,8 @@ inline void AddCustomTicks(const double* values, const char** labels, int n, ImV } 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, ImPlotAxisFlags_Invert)), - lock_min(HasFlag(axis->Flags, ImPlotAxisFlags_LockMin)), - lock_max(HasFlag(axis->Flags, ImPlotAxisFlags_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) { +void UpdateAxisColor(int axis_flag, ImPlotAxisColor* 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 = ImGui::GetColorU32(col_Axis); col->Minor = ImGui::GetColorU32(col_Axis * ImVec4(1, 1, 1, 0.25f)); @@ -772,16 +777,16 @@ struct ImPlotAxisScale { 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) {} + YPadCalculator(const ImPlotAxisState* axis_states, const float* max_label_widths, float txt_off) + : ImPlotAxisStates(axis_states), MaxLabelWidths(max_label_widths), TxtOff(txt_off) {} float operator()(int y_axis) { ImPlotState& plot = *gp.CurrentPlot; - if (!AxisStates[y_axis].present) { return 0; } + if (!ImPlotAxisStates[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) { + if (ImPlotAxisStates[y_axis].present_so_far >= 3) { pad_result += 6.0f; } if (!HasFlag(plot.YAxis[y_axis].Flags, ImPlotAxisFlags_TickLabels)) { @@ -792,7 +797,7 @@ class YPadCalculator { } private: - const AxisState* const AxisStates; + const ImPlotAxisState* const ImPlotAxisStates; const float* const MaxLabelWidths; const float TxtOff; }; @@ -885,17 +890,14 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons } // 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); + gp.X = ImPlotAxisState(plot.XAxis, gp.NextPlotData.HasXRange, gp.NextPlotData.XRangeCond, true, 0); + gp.Y[0] = ImPlotAxisState(plot.YAxis[0], gp.NextPlotData.HasYRange[0], gp.NextPlotData.YRangeCond[0], true, 0); + gp.Y[1] = ImPlotAxisState(plot.YAxis[1], gp.NextPlotData.HasYRange[1], gp.NextPlotData.YRangeCond[1], + HasFlag(plot.Flags, ImPlotFlags_YAxis2), gp.Y[0].present_so_far); + gp.Y[2] = ImPlotAxisState(plot.YAxis[2], gp.NextPlotData.HasYRange[2], gp.NextPlotData.YRangeCond[2], + HasFlag(plot.Flags, ImPlotFlags_YAxis3), gp.Y[1].present_so_far); - gp.LockPlot = x.lock && y[0].lock && - ( HasFlag(plot.Flags, ImPlotFlags_YAxis2) ? y[1].lock : true ) && - ( HasFlag(plot.Flags, ImPlotFlags_YAxis3) ? y[2].lock : true ); + gp.LockPlot = gp.X.lock && gp.Y[0].lock && gp.Y[1].lock && gp.Y[2].lock; // CONSTRAINTS ------------------------------------------------------------ @@ -977,7 +979,7 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons HasFlag(plot.XAxis.Flags, ImPlotAxisFlags_TickLabels)) && plot.XAxis.Divisions > 1; for (int i = 0; i < MAX_Y_AXES; i++) { gp.RenderY[i] = - y[i].present && + gp.Y[i].present && (HasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_GridLines) || HasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_TickMarks) || HasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_TickLabels)) && plot.YAxis[i].Divisions > 1; @@ -998,7 +1000,7 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons 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, ImPlotAxisFlags_TickLabels)) { + if (gp.Y[i].present && HasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_TickLabels)) { LabelTicks(gp.YTicks[i], HasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_Scientific), gp.YTickLabels[i]); for (int t = 0; t < gp.YTicks[i].Size; t++) { ImPlotTick *yt = &gp.YTicks[i][t]; @@ -1013,7 +1015,7 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons 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, ImPlotAxisFlags_TickLabels) ? txt_height + txt_off : 0) + (x_label ? txt_height + txt_off : 0); - YPadCalculator y_axis_pad(y, max_label_width, txt_off); + YPadCalculator y_axis_pad(gp.Y, max_label_width, txt_off); const float pad_left = y_axis_pad(0) + (y_label ? txt_height + txt_off : 0); const float pad_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)); @@ -1031,7 +1033,7 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons // 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.Y[1].present ? gp.BB_Grid.Max.x : (gp.AxisLabelReference[1] + y_axis_pad(1) + 6); @@ -1047,9 +1049,9 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons ImVec2(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)), + gp.Y[0].present && (yAxisRegion_bb[0].Contains(IO.MousePos) || centralRegion.Contains(IO.MousePos)), + gp.Y[1].present && (yAxisRegion_bb[1].Contains(IO.MousePos) || centralRegion.Contains(IO.MousePos)), + gp.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]; @@ -1085,7 +1087,6 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons // DRAG INPUT ------------------------------------------------------------- - // end drags if (plot.XAxis.Dragging && (IO.MouseReleased[0] || !IO.MouseDown[0])) { plot.XAxis.Dragging = false; @@ -1102,33 +1103,33 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons // do drag if (drag_in_progress) { UpdateTransformCache(); - if (!x.lock && plot.XAxis.Dragging) { + if (!gp.X.lock && plot.XAxis.Dragging) { ImPlotPoint plot_tl = PixelsToPlot(gp.BB_Grid.Min - IO.MouseDelta, 0); ImPlotPoint 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 (!gp.X.lock_min) + plot.XAxis.Range.Min = gp.X.invert ? plot_br.x : plot_tl.x; + if (!gp.X.lock_max) + plot.XAxis.Range.Max = gp.X.invert ? plot_tl.x : plot_br.x; } for (int i = 0; i < MAX_Y_AXES; i++) { - if (!y[i].lock && plot.YAxis[i].Dragging) { + if (!gp.Y[i].lock && plot.YAxis[i].Dragging) { ImPlotPoint plot_tl = PixelsToPlot(gp.BB_Grid.Min - IO.MouseDelta, i); ImPlotPoint 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 (!gp.Y[i].lock_min) + plot.YAxis[i].Range.Min = gp.Y[i].invert ? plot_tl.y : plot_br.y; + if (!gp.Y[i].lock_max) + plot.YAxis[i].Range.Max = gp.Y[i].invert ? plot_br.y : plot_tl.y; } } // Set the mouse cursor based on which axes are moving. int direction = 0; - if (!x.lock && plot.XAxis.Dragging) { + if (!gp.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) { + if (!gp.Y[i].present) { continue; } + if (!gp.Y[i].lock && plot.YAxis[i].Dragging) { direction |= (1 << 2); break; } @@ -1165,25 +1166,25 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons 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.0f, 1.0f); float ty = Remap(IO.MousePos.y, gp.BB_Grid.Min.y, gp.BB_Grid.Max.y, 0.0f, 1.0f); - if (hov_x_axis_region && !x.lock) { + if (hov_x_axis_region && !gp.X.lock) { ImPlotAxisScale axis_scale(0, tx, ty, zoom_rate); const ImPlotPoint& plot_tl = axis_scale.Min; const ImPlotPoint& 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; + if (!gp.X.lock_min) + plot.XAxis.Range.Min = gp.X.invert ? plot_br.x : plot_tl.x; + if (!gp.X.lock_max) + plot.XAxis.Range.Max = gp.X.invert ? plot_tl.x : plot_br.x; } for (int i = 0; i < MAX_Y_AXES; i++) { - if (hov_y_axis_region[i] && !y[i].lock) { + if (hov_y_axis_region[i] && !gp.Y[i].lock) { ImPlotAxisScale axis_scale(i, tx, ty, zoom_rate); const ImPlotPoint& plot_tl = axis_scale.Min; const ImPlotPoint& 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; + if (!gp.Y[i].lock_min) + plot.YAxis[i].Range.Min = gp.Y[i].invert ? plot_tl.y : plot_br.y; + if (!gp.Y[i].lock_max) + plot.YAxis[i].Range.Max = gp.Y[i].invert ? plot_br.y : plot_tl.y; } } } @@ -1197,16 +1198,16 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons if (HasFlag(plot.Flags, ImPlotFlags_BoxSelect) && ImFabs(select_size.x) > 2 && ImFabs(select_size.y) > 2) { ImPlotPoint p1 = PixelsToPlot(plot.SelectStart); ImPlotPoint p2 = PixelsToPlot(IO.MousePos); - if (!x.lock_min && !IO.KeyAlt) + if (!gp.X.lock_min && !IO.KeyAlt) plot.XAxis.Range.Min = ImMin(p1.x, p2.x); - if (!x.lock_max && !IO.KeyAlt) + if (!gp.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) + if (!gp.Y[i].lock_min && !IO.KeyShift) plot.YAxis[i].Range.Min = ImMin(p1.y, p2.y); - if (!y[i].lock_max && !IO.KeyShift) + if (!gp.Y[i].lock_max && !IO.KeyShift) plot.YAxis[i].Range.Max = ImMax(p1.y, p2.y); } } @@ -1221,7 +1222,7 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons plot.Selecting = false; } // begin selection or query - if (!gp.LockPlot && gp.Hov_Frame && gp.Hov_Grid && IO.MouseClicked[1]) { + if (gp.Hov_Frame && gp.Hov_Grid && IO.MouseClicked[1]) { plot.SelectStart = IO.MousePos; plot.Selecting = true; } @@ -1331,7 +1332,7 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons } for (int i = 0; i < MAX_Y_AXES; i++) { - if (y[i].present && HasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_GridLines)) { + if (gp.Y[i].present && HasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_GridLines)) { for (int t = 0; t < gp.YTicks[i].Size; t++) { ImPlotTick *yt = &gp.YTicks[i][t]; DrawList.AddLine(ImVec2(gp.BB_Grid.Min.x, yt->PixelPos), ImVec2(gp.BB_Grid.Max.x, yt->PixelPos), yt->Major ? gp.Col_Y[i].Major : gp.Col_Y[i].Minor, 1); @@ -1364,7 +1365,7 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons } ImGui::PushClipRect(gp.BB_Frame.Min, gp.BB_Frame.Max, true); for (int i = 0; i < MAX_Y_AXES; i++) { - if (y[i].present && HasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_TickLabels)) { + if (gp.Y[i].present && HasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_TickLabels)) { const float x_start = gp.AxisLabelReference[i] + ((i == 0) ? @@ -1412,40 +1413,51 @@ bool DragFloat(const char* label, float* v, float v_speed, float v_min, f return ImGui::DragScalar(label, ImGuiDataType_Float, v, v_speed, &v_min, &v_max, "%.3f", 1); } -inline void AxisMenu(ImPlotAxis& Axis) { - ImGui::PushItemWidth(75); - bool lock_min = HasFlag(Axis.Flags, ImPlotAxisFlags_LockMin); - bool lock_max = HasFlag(Axis.Flags, ImPlotAxisFlags_LockMax); - bool invert = HasFlag(Axis.Flags, ImPlotAxisFlags_Invert); +inline void BeginDisabledControls(bool cond) { + if (cond) { + ImGui::PushItemFlag(ImGuiItemFlags_Disabled, true); + ImGui::PushStyleVar(ImGuiStyleVar_Alpha, ImGui::GetStyle().Alpha * 0.25f); + } +} + +inline void EndDisabledControls(bool cond) { + if (cond) { + ImGui::PopItemFlag(); + ImGui::PopStyleVar(); + } +} + +inline void AxisMenu(ImPlotAxis& Axis, ImPlotAxisState& state) { + ImGui::PushItemWidth(75); + bool total_lock = state.has_range && state.range_cond == ImGuiCond_Always; bool logscale = HasFlag(Axis.Flags, ImPlotAxisFlags_LogScale); bool grid = HasFlag(Axis.Flags, ImPlotAxisFlags_GridLines); bool ticks = HasFlag(Axis.Flags, ImPlotAxisFlags_TickMarks); bool labels = HasFlag(Axis.Flags, ImPlotAxisFlags_TickLabels); - if (ImGui::Checkbox("##LockMin", &lock_min)) - FlipFlag(Axis.Flags, ImPlotAxisFlags_LockMin); - ImGui::SameLine(); - if (lock_min) { - ImGui::PushItemFlag(ImGuiItemFlags_Disabled, true); - ImGui::PushStyleVar(ImGuiStyleVar_Alpha, ImGui::GetStyle().Alpha * 0.25f); - } - DragFloat("Min", &Axis.Range.Min, 0.01f + 0.01f * (float)Axis.Range.Size(), -HUGE_VAL, Axis.Range.Max - DBL_EPSILON); - if (lock_min) { - ImGui::PopItemFlag(); - ImGui::PopStyleVar(); } - if (ImGui::Checkbox("##LockMax", &lock_max)) - FlipFlag(Axis.Flags, ImPlotAxisFlags_LockMax); + BeginDisabledControls(total_lock); + if (ImGui::Checkbox("##LockMin", &state.lock_min)) + FlipFlag(Axis.Flags, ImPlotAxisFlags_LockMin); + EndDisabledControls(total_lock); + ImGui::SameLine(); - if (lock_max) { - ImGui::PushItemFlag(ImGuiItemFlags_Disabled, true); - ImGui::PushStyleVar(ImGuiStyleVar_Alpha, ImGui::GetStyle().Alpha * 0.25f); } + BeginDisabledControls(state.lock_min); + DragFloat("Min", &Axis.Range.Min, 0.01f + 0.01f * (float)Axis.Range.Size(), -HUGE_VAL, Axis.Range.Max - DBL_EPSILON); + EndDisabledControls(state.lock_min); + + BeginDisabledControls(total_lock); + if (ImGui::Checkbox("##LockMax", &state.lock_max)) + FlipFlag(Axis.Flags, ImPlotAxisFlags_LockMax); + EndDisabledControls(total_lock); + + ImGui::SameLine(); + BeginDisabledControls(state.lock_max); DragFloat("Max", &Axis.Range.Max, 0.01f + 0.01f * (float)Axis.Range.Size(), Axis.Range.Min + DBL_EPSILON, HUGE_VAL); - if (lock_max) { - ImGui::PopItemFlag(); - ImGui::PopStyleVar(); - } + EndDisabledControls(state.lock_max); + ImGui::Separator(); - if (ImGui::Checkbox("Invert", &invert)) + + if (ImGui::Checkbox("Invert", &state.invert)) FlipFlag(Axis.Flags, ImPlotAxisFlags_Invert); if (ImGui::Checkbox("Log Scale", &logscale)) FlipFlag(Axis.Flags, ImPlotAxisFlags_LogScale); @@ -1456,12 +1468,13 @@ inline void AxisMenu(ImPlotAxis& Axis) { FlipFlag(Axis.Flags, ImPlotAxisFlags_TickMarks); if (ImGui::Checkbox("Labels", &labels)) FlipFlag(Axis.Flags, ImPlotAxisFlags_TickLabels); + } void PlotContextMenu(ImPlotState& plot) { if (ImGui::BeginMenu("X-Axis")) { ImGui::PushID("X"); - AxisMenu(plot.XAxis); + AxisMenu(plot.XAxis, gp.X); ImGui::PopID(); ImGui::EndMenu(); } @@ -1480,7 +1493,7 @@ void PlotContextMenu(ImPlotState& plot) { } if (ImGui::BeginMenu(buf)) { ImGui::PushID(i); - AxisMenu(plot.YAxis[i]); + AxisMenu(plot.YAxis[i], gp.Y[i]); ImGui::PopID(); ImGui::EndMenu(); } @@ -1565,16 +1578,7 @@ void EndPlot() { // AXIS STATES ------------------------------------------------------------ - // TODO: Move this into gp to avoid repetition - 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 any_y_locked = y[0].lock || y[1].lock || y[2].lock; + const bool any_y_locked = gp.Y[0].lock || gp.Y[1].present ? gp.Y[1].lock : false || gp.Y[2].present ? gp.Y[2].lock : false; const bool any_y_dragging = plot.YAxis[0].Dragging || plot.YAxis[1].Dragging || plot.YAxis[2].Dragging; @@ -1593,7 +1597,7 @@ void EndPlot() { ImGui::PushClipRect(gp.BB_Grid.Min, ImVec2(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; } + if (!gp.Y[i].present) { continue; } axis_count++; if (!HasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_TickMarks)) { continue; } @@ -1632,7 +1636,7 @@ 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 ((x.lock || IO.KeyAlt)) { + else if ((gp.X.lock || IO.KeyAlt)) { 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); } @@ -2402,6 +2406,12 @@ inline void PlotEx(const char* label_id, Getter getter, int count, int offset) ImPlotPoint p = getter(i); FitPoint(p); } + if (rend_fill) { + ImPlotPoint p1 = getter(0); + ImPlotPoint p2 = getter(count - 1); + p1.y = 0; p2.y = 0; + FitPoint(p1); FitPoint(p2); + } } PushPlotClipRect(); // render fill diff --git a/implot_demo.cpp b/implot_demo.cpp index a42de28..1523037 100644 --- a/implot_demo.cpp +++ b/implot_demo.cpp @@ -67,7 +67,7 @@ struct ScrollingData { int Offset; ImVector Data; ScrollingData() { - MaxSize = 1000; + MaxSize = 2000; Offset = 0; Data.reserve(MaxSize); } @@ -93,7 +93,7 @@ struct RollingData { ImVector Data; RollingData() { Span = 10.0f; - Data.reserve(1000); + Data.reserve(2000); } void AddPoint(t_float x, t_float y) { t_float xmod = Fmod(x, Span); @@ -375,14 +375,20 @@ void ShowDemoWindow(bool* p_open) { sdata2.AddPoint(t, mouse.y * 0.0005f); rdata2.AddPoint(t, mouse.y * 0.0005f); } - ImPlot::SetNextPlotLimitsX(t - 10, t, paused ? ImGuiCond_Once : ImGuiCond_Always); + static float history = 10.0f; + ImGui::SliderFloat("History",&history,1,30,"%.1f s"); + rdata1.Span = history; + rdata2.Span = history; + ImPlot::SetNextPlotLimitsX(t - history, t, paused ? ImGuiCond_Once : ImGuiCond_Always); static int rt_axis = ImPlotAxisFlags_Default & ~ImPlotAxisFlags_TickLabels; - if (ImPlot::BeginPlot("##Scrolling", NULL, NULL, ImVec2(-1,150), ImPlotFlags_Default, rt_axis, rt_axis)) { + if (ImPlot::BeginPlot("##Scrolling", NULL, NULL, ImVec2(-1,150), ImPlotFlags_Default, rt_axis, rt_axis | ImPlotAxisFlags_LockMin)) { ImPlot::PlotLine("Data 1", &sdata1.Data[0].x, &sdata1.Data[0].y, sdata1.Data.size(), sdata1.Offset, 2 * sizeof(t_float)); + ImPlot::PushStyleColor(ImPlotCol_Fill, ImVec4(1,0,0,0.25f)); ImPlot::PlotLine("Data 2", &sdata2.Data[0].x, &sdata2.Data[0].y, sdata2.Data.size(), sdata2.Offset, 2 * sizeof(t_float)); + ImPlot::PopStyleColor(); ImPlot::EndPlot(); } - ImPlot::SetNextPlotLimitsX(0, 10, ImGuiCond_Always); + ImPlot::SetNextPlotLimitsX(0, history, ImGuiCond_Always); if (ImPlot::BeginPlot("##Rolling", NULL, NULL, ImVec2(-1,150), ImPlotFlags_Default, rt_axis, rt_axis)) { ImPlot::PlotLine("Data 1", &rdata1.Data[0].x, &rdata1.Data[0].y, rdata1.Data.size(), 0, 2 * sizeof(t_float)); ImPlot::PlotLine("Data 2", &rdata2.Data[0].x, &rdata2.Data[0].y, rdata2.Data.size(), 0, 2 * sizeof(t_float)); @@ -632,13 +638,14 @@ void ShowDemoWindow(bool* p_open) { } //------------------------------------------------------------------------- if (ImGui::CollapsingHeader("Drag and Drop")) { + const int K_CHANNELS = 9; srand((int)(10000000 * ImGui::GetTime())); static bool paused = false; static bool init = true; - static ScrollingData data[10]; - static bool show[10]; + static ScrollingData data[K_CHANNELS]; + static bool show[K_CHANNELS]; if (init) { - for (int i = 0; i < 10; ++i) { + for (int i = 0; i < K_CHANNELS; ++i) { show[i] = false; } init = false; @@ -646,7 +653,7 @@ void ShowDemoWindow(bool* p_open) { ImGui::BulletText("Drag data items from the left column onto the plot."); ImGui::BeginGroup(); if (ImGui::Button("Clear", ImVec2(100, 0))) { - for (int i = 0; i < 10; ++i) { + for (int i = 0; i < K_CHANNELS; ++i) { show[i] = false; data[i].Data.shrink(0); data[i].Offset = 0; @@ -655,8 +662,8 @@ void ShowDemoWindow(bool* p_open) { if (ImGui::Button(paused ? "Resume" : "Pause", ImVec2(100,0))) paused = !paused; ImGui::Separator(); - for (int i = 0; i < 10; ++i) { - char label[8]; + for (int i = 0; i < K_CHANNELS; ++i) { + char label[K_CHANNELS]; sprintf(label, show[i] ? "data_%d*" : "data_%d", i); ImGui::Selectable(label, false, 0, ImVec2(100, 0)); if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_None)) { @@ -670,18 +677,16 @@ void ShowDemoWindow(bool* p_open) { static t_float t = 0; if (!paused) { t += ImGui::GetIO().DeltaTime; - for (int i = 0; i < 10; ++i) { + for (int i = 0; i < K_CHANNELS; ++i) { if (show[i]) - data[i].AddPoint(t, data[i].Data.empty() ? - 0.25f + 0.5f * (t_float)rand() / t_float(RAND_MAX) : - data[i].Data.back().y + (0.005f + 0.0002f * (t_float)rand() / t_float(RAND_MAX)) * (-1 + 2 * (t_float)rand() / t_float(RAND_MAX))); + data[i].AddPoint(t, (i+1)*0.1f + RandomRange(-0.01f,0.01f)); } } ImPlot::SetNextPlotLimitsX((double)t - 10, t, paused ? ImGuiCond_Once : ImGuiCond_Always); if (ImPlot::BeginPlot("##DND")) { - for (int i = 0; i < 10; ++i) { + for (int i = 0; i < K_CHANNELS; ++i) { if (show[i] && data[i].Data.size() > 0) { - char label[8]; + char label[K_CHANNELS]; sprintf(label, "data_%d", i); ImPlot::PlotLine(label, &data[i].Data[0].x, &data[i].Data[0].y, data[i].Data.size(), data[i].Offset, 2 * sizeof(t_float)); } From 97c2f06edaa25bfd98ea78f090882be7ef52bf08 Mon Sep 17 00:00:00 2001 From: Evan Pezent Date: Thu, 4 Jun 2020 00:17:38 -0500 Subject: [PATCH 3/5] Fix trivial mistake in demo. --- implot_demo.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/implot_demo.cpp b/implot_demo.cpp index 1523037..1439b85 100644 --- a/implot_demo.cpp +++ b/implot_demo.cpp @@ -663,7 +663,7 @@ void ShowDemoWindow(bool* p_open) { paused = !paused; ImGui::Separator(); for (int i = 0; i < K_CHANNELS; ++i) { - char label[K_CHANNELS]; + char label[8]; sprintf(label, show[i] ? "data_%d*" : "data_%d", i); ImGui::Selectable(label, false, 0, ImVec2(100, 0)); if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_None)) { @@ -931,4 +931,4 @@ void ShowDemoWindow(bool* p_open) { ImGui::End(); } -} // namespace ImPlot \ No newline at end of file +} // namespace ImPlot From 2a5a78565bbea6489dfb078bd7aa299649e35e47 Mon Sep 17 00:00:00 2001 From: Evan Pezent Date: Thu, 4 Jun 2020 09:56:50 -0500 Subject: [PATCH 4/5] internal refactors and misc improvements --- implot.cpp | 494 +++++++++++++++++++++++++----------------------- implot.h | 26 +-- implot_demo.cpp | 18 +- 3 files changed, 278 insertions(+), 260 deletions(-) diff --git a/implot.cpp b/implot.cpp index 85b66bf..f242d39 100644 --- a/implot.cpp +++ b/implot.cpp @@ -31,6 +31,7 @@ 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/06/03 (0.3) - The signature and behavior of PlotPieChart was changed so that data with sum less than 1 can optionally be normalized. The label format can now be specified as well. - 2020/06/01 (0.3) - SetPalette was changed to `SetColormap` for consistency with other plotting libraries. `RestorePalette` was removed. Use `SetColormap(ImPlotColormap_Default)`. - 2020/05/31 (0.3) - Plot functions taking custom ImVec2* getters were removed. Use the ImPlotPoint* getter versions instead. - 2020/05/29 (0.3) - The signature of ImPlotLimits::Contains was changed to take two doubles instead of ImVec2 @@ -159,45 +160,55 @@ void FillRange(ImVector& buffer, int n, T vmin, T vmax) { } } -/// Returns true if a flag is set +// Returns true if a flag is set template inline bool HasFlag(TSet set, TFlag flag) { return (set & flag) == flag; } -/// Flips a flag in a flagset +// Flips a flag in a flagset template inline void FlipFlag(TSet& set, TFlag flag) { HasFlag(set, flag) ? set &= ~flag : set |= flag; } -/// Linearly remaps x from [x0 x1] to [y0 y1]. +// Linearly remaps x from [x0 x1] to [y0 y1]. template inline T Remap(T x, T x0, T x1, T y0, T y1) { return y0 + (x - x0) * (y1 - y0) / (x1 - x0); } -/// Turns NANs to 0s +// Turns NANs to 0s inline double ConstrainNan(double val) { return isnan(val) ? 0 : val; } -/// Turns infinity to floating point maximums +// Turns infinity to floating point maximums inline double ConstrainInf(double val) { return val == HUGE_VAL ? DBL_MAX : val == -HUGE_VAL ? - DBL_MAX : val; } -/// Turns numbers less than or equal to 0 to 0.001 (sort of arbitrary, is there a better way?) +// Turns numbers less than or equal to 0 to 0.001 (sort of arbitrary, is there a better way?) inline double ConstrainLog(double val) { return val <= 0 ? 0.001f : val; } -/// Returns true if val is NAN or INFINITY +// Returns true if val is NAN or INFINITY inline bool NanOrInf(double val) { return val == HUGE_VAL || val == -HUGE_VAL || isnan(val); } -/// Draws vertical text. The position is the bottom left of the text rect. +// Computes order of magnitude of double. +// inline int OrderOfMagnitude(double val) { +// return val == 0 ? 0 : (int)(floor(log10(fabs(val)))); +// } + +// Returns the precision required for a order of magnitude. +// inline int OrderToPrecision(int order) { +// return order > 0 ? 0 : 1 - order; +// } + +// Draws vertical text. The position is the bottom left of the text rect. inline void AddTextVertical(ImDrawList *DrawList, const char *text, ImVec2 pos, ImU32 text_color) { pos.x = IM_ROUND(pos.x); pos.y = IM_ROUND(pos.y); @@ -219,7 +230,7 @@ inline void AddTextVertical(ImDrawList *DrawList, const char *text, ImVec2 pos, } } -/// Calculates the size of vertical text +// Calculates the size of vertical text inline ImVec2 CalcTextSizeVertical(const char *text) { ImVec2 sz = ImGui::CalcTextSize(text); return ImVec2(sz.y, sz.x); @@ -237,7 +248,7 @@ ImVec4 NextColor(); // Structs //----------------------------------------------------------------------------- -/// Tick mark info +// Tick mark info struct ImPlotTick { ImPlotTick(double value, bool major, bool render_label = true) { PlotPos = value; @@ -254,7 +265,7 @@ struct ImPlotTick { bool Labeled; }; -/// Axis state information that must persist after EndPlot +// Axis state information that must persist after EndPlot struct ImPlotAxis { ImPlotAxis() { Dragging = false; @@ -271,39 +282,32 @@ struct ImPlotAxis { ImPlotAxisFlags Flags, PreviousFlags; }; -/// Axis state information only needed between BeginPlot/EndPlot +// Axis state information only needed between BeginPlot/EndPlot struct ImPlotAxisState { - ImPlotAxis* axis; - bool has_range; - ImGuiCond range_cond; - bool present; - int present_so_far; - bool invert; - bool lock_min; - bool lock_max; - bool lock; - ImPlotAxisState(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)), - invert(HasFlag(axis->Flags, ImPlotAxisFlags_Invert)), - lock_min(HasFlag(axis->Flags, ImPlotAxisFlags_LockMin) || (has_range && range_cond == ImGuiCond_Always)), - lock_max(HasFlag(axis->Flags, ImPlotAxisFlags_LockMax) || (has_range && range_cond == ImGuiCond_Always)), - lock(!present || ((lock_min && lock_max) || (has_range && range_cond == ImGuiCond_Always))) {} + ImPlotAxis* Axis; + bool HasRange; + ImGuiCond RangeCond; + bool Present; + int PresentSoFar; + bool Invert; + bool LockMin; + bool LockMax; + bool Lock; + ImPlotAxisState(ImPlotAxis& axis, bool has_range, ImGuiCond range_cond, bool present, int previous_present) : + Axis(&axis), + HasRange(has_range), + RangeCond(range_cond), + Present(present), + PresentSoFar(previous_present + (Present ? 1 : 0)), + Invert(HasFlag(Axis->Flags, ImPlotAxisFlags_Invert)), + LockMin(HasFlag(Axis->Flags, ImPlotAxisFlags_LockMin) || (HasRange && RangeCond == ImGuiCond_Always)), + LockMax(HasFlag(Axis->Flags, ImPlotAxisFlags_LockMax) || (HasRange && RangeCond == ImGuiCond_Always)), + Lock(!Present || ((LockMin && LockMax) || (HasRange && RangeCond == ImGuiCond_Always))) + {} - ImPlotAxisState() - : axis(), - has_range(), - range_cond(), - present(), - present_so_far(), - invert(), - lock_min(), - lock_max(), - lock() {} + ImPlotAxisState() : + Axis(), HasRange(), RangeCond(), Present(), PresentSoFar(),Invert(),LockMin(), LockMax(), Lock() + {} }; struct ImPlotAxisColor { @@ -311,7 +315,7 @@ struct ImPlotAxisColor { ImU32 Major, Minor, Txt; }; -/// State information for Plot items +// State information for Plot items struct ImPlotItem { ImPlotItem() { Show = true; @@ -328,7 +332,7 @@ struct ImPlotItem { ImGuiID ID; }; -/// Holds Plot state information that must persist after EndPlot +// Holds Plot state information that must persist after EndPlot struct ImPlotState { ImPlotState() { Selecting = Querying = Queried = DraggingQuery = false; @@ -346,7 +350,7 @@ struct ImPlotState { bool Queried; bool DraggingQuery; ImVec2 QueryStart; - ImRect QueryRect; // relative to BB_grid!! + ImRect QueryRect; // relative to BB_Plot!! ImPlotAxis XAxis; ImPlotAxis YAxis[MAX_Y_AXES]; @@ -375,7 +379,7 @@ struct ImPlotNextPlotData { bool ShowDefaultTicksY[MAX_Y_AXES]; }; -/// Holds Plot state information that must persist only between calls to BeginPlot()/EndPlot() +// Holds Plot state information that must persist only between calls to BeginPlot()/EndPlot() struct ImPlotContext { ImPlotContext() : RenderX(), RenderY() { ChildWindowMade = false; @@ -418,9 +422,9 @@ struct ImPlotContext { CurrentPlot = NULL; } - /// ALl Plots + // ALl Plots ImPool Plots; - /// Current Plot + // Current Plot ImPlotState* CurrentPlot; // Legend ImVector LegendIndices; @@ -428,7 +432,7 @@ struct ImPlotContext { // Bounding regions ImRect BB_Frame; ImRect BB_Canvas; - ImRect BB_Grid; + ImRect BB_Plot; // Cached Colors ImU32 Col_Frame, Col_Bg, Col_Border, Col_Txt, Col_TxtDis, @@ -458,7 +462,7 @@ struct ImPlotContext { bool FitY[MAX_Y_AXES]; // Hover states bool Hov_Frame; - bool Hov_Grid; + bool Hov_Plot; // Render flags bool RenderX, RenderY[MAX_Y_AXES]; // Lock info @@ -478,14 +482,14 @@ struct ImPlotContext { int DigitalPlotOffset; }; -/// Global plot context +// Global plot context static ImPlotContext gp; //----------------------------------------------------------------------------- // Context Utils //----------------------------------------------------------------------------- -/// Returns the next unused default plot color +// Returns the next unused default plot color ImVec4 NextColor() { ImVec4 col = gp.Colormap[gp.CurrentPlot->ColorIdx % gp.ColormapSize]; gp.CurrentPlot->ColorIdx++; @@ -513,10 +517,10 @@ inline void UpdateTransformCache() { // get pixels for transforms for (int i = 0; i < MAX_Y_AXES; i++) { - gp.PixelRange[i] = ImRect(HasFlag(gp.CurrentPlot->XAxis.Flags, ImPlotAxisFlags_Invert) ? gp.BB_Grid.Max.x : gp.BB_Grid.Min.x, - HasFlag(gp.CurrentPlot->YAxis[i].Flags, ImPlotAxisFlags_Invert) ? gp.BB_Grid.Min.y : gp.BB_Grid.Max.y, - HasFlag(gp.CurrentPlot->XAxis.Flags, ImPlotAxisFlags_Invert) ? gp.BB_Grid.Min.x : gp.BB_Grid.Max.x, - HasFlag(gp.CurrentPlot->YAxis[i].Flags, ImPlotAxisFlags_Invert) ? gp.BB_Grid.Max.y : gp.BB_Grid.Min.y); + gp.PixelRange[i] = ImRect(HasFlag(gp.CurrentPlot->XAxis.Flags, ImPlotAxisFlags_Invert) ? gp.BB_Plot.Max.x : gp.BB_Plot.Min.x, + HasFlag(gp.CurrentPlot->YAxis[i].Flags, ImPlotAxisFlags_Invert) ? gp.BB_Plot.Min.y : gp.BB_Plot.Max.y, + HasFlag(gp.CurrentPlot->XAxis.Flags, ImPlotAxisFlags_Invert) ? gp.BB_Plot.Min.x : gp.BB_Plot.Max.x, + HasFlag(gp.CurrentPlot->YAxis[i].Flags, ImPlotAxisFlags_Invert) ? gp.BB_Plot.Max.y : gp.BB_Plot.Min.y); gp.My[i] = (gp.PixelRange[i].Max.y - gp.PixelRange[i].Min.y) / gp.CurrentPlot->YAxis[i].Range.Size(); } @@ -665,8 +669,8 @@ const char* GetLegendLabel(int i) { // Tick Utils //----------------------------------------------------------------------------- -/// Utility function to that rounds x to powers of 2,5 and 10 for generating axis labels -/// Taken from Graphics Gems 1 Chapter 11.2, "Nice Numbers for Graph Labels" +// Utility function to that rounds x to powers of 2,5 and 10 for generating axis labels +// Taken from Graphics Gems 1 Chapter 11.2, "Nice Numbers for Graph Labels" inline double NiceNum(double x, bool round) { double f; /* fractional part of x */ double nf; /* nice, rounded fraction */ @@ -737,7 +741,7 @@ inline void LabelTicks(ImVector &ticks, bool scientific, ImGuiTextBu if (scientific) sprintf(temp, "%.0e", tk->PlotPos); else - sprintf(temp, "%g", tk->PlotPos); + sprintf(temp, "%.10g", tk->PlotPos); buffer.append(temp, temp + strlen(temp) + 1); tk->Size = ImGui::CalcTextSize(buffer.Buf.Data + tk->TextOffset); tk->Labeled = true; @@ -758,23 +762,13 @@ inline void AddCustomTicks(const double* values, const char** labels, int n, ImV } } -namespace { - -void UpdateAxisColor(int axis_flag, ImPlotAxisColor* 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 = ImGui::GetColorU32(col_Axis); - col->Minor = ImGui::GetColorU32(col_Axis * ImVec4(1, 1, 1, 0.25f)); - col->Txt = ImGui::GetColorU32(ImVec4(col_Axis.x, col_Axis.y, col_Axis.z, 1)); +inline float MaxTickLabelWidth(ImVector& ticks) { + float w = 0; + for (int i = 0; i < ticks.Size; ++i) + w = ticks[i].Size.x > w ? ticks[i].Size.x : w; + return w; } -struct ImPlotAxisScale { - ImPlotAxisScale(int y_axis, float tx, float ty, float zoom_rate) { - Min = PixelsToPlot(gp.BB_Grid.Min - gp.BB_Grid.GetSize() * ImVec2(tx * zoom_rate, ty * zoom_rate), y_axis); - Max = PixelsToPlot(gp.BB_Grid.Max + gp.BB_Grid.GetSize() * ImVec2((1 - tx) * zoom_rate, (1 - ty) * zoom_rate), y_axis); - } - ImPlotPoint Min, Max; -}; - class YPadCalculator { public: YPadCalculator(const ImPlotAxisState* axis_states, const float* max_label_widths, float txt_off) @@ -782,11 +776,11 @@ class YPadCalculator { float operator()(int y_axis) { ImPlotState& plot = *gp.CurrentPlot; - if (!ImPlotAxisStates[y_axis].present) { return 0; } + if (!ImPlotAxisStates[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 (ImPlotAxisStates[y_axis].present_so_far >= 3) { + if (ImPlotAxisStates[y_axis].PresentSoFar >= 3) { pad_result += 6.0f; } if (!HasFlag(plot.YAxis[y_axis].Flags, ImPlotAxisFlags_TickLabels)) { @@ -801,7 +795,25 @@ class YPadCalculator { const float* const MaxLabelWidths; const float TxtOff; }; -} // namespace + +//----------------------------------------------------------------------------- +// Axis Utils +//----------------------------------------------------------------------------- + +void UpdateAxisColor(int axis_flag, ImPlotAxisColor* 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 = ImGui::GetColorU32(col_Axis); + col->Minor = ImGui::GetColorU32(col_Axis * ImVec4(1, 1, 1, 0.25f)); + col->Txt = ImGui::GetColorU32(ImVec4(col_Axis.x, col_Axis.y, col_Axis.z, 1)); +} + +struct ImPlotAxisScale { + ImPlotAxisScale(int y_axis, float tx, float ty, float zoom_rate) { + Min = PixelsToPlot(gp.BB_Plot.Min - gp.BB_Plot.GetSize() * ImVec2(tx * zoom_rate, ty * zoom_rate), y_axis); + Max = PixelsToPlot(gp.BB_Plot.Max + gp.BB_Plot.GetSize() * ImVec2((1 - tx) * zoom_rate, (1 - ty) * zoom_rate), y_axis); + } + ImPlotPoint Min, Max; +}; //----------------------------------------------------------------------------- // BeginPlot() @@ -893,11 +905,11 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons gp.X = ImPlotAxisState(plot.XAxis, gp.NextPlotData.HasXRange, gp.NextPlotData.XRangeCond, true, 0); gp.Y[0] = ImPlotAxisState(plot.YAxis[0], gp.NextPlotData.HasYRange[0], gp.NextPlotData.YRangeCond[0], true, 0); gp.Y[1] = ImPlotAxisState(plot.YAxis[1], gp.NextPlotData.HasYRange[1], gp.NextPlotData.YRangeCond[1], - HasFlag(plot.Flags, ImPlotFlags_YAxis2), gp.Y[0].present_so_far); + HasFlag(plot.Flags, ImPlotFlags_YAxis2), gp.Y[0].PresentSoFar); gp.Y[2] = ImPlotAxisState(plot.YAxis[2], gp.NextPlotData.HasYRange[2], gp.NextPlotData.YRangeCond[2], - HasFlag(plot.Flags, ImPlotFlags_YAxis3), gp.Y[1].present_so_far); + HasFlag(plot.Flags, ImPlotFlags_YAxis3), gp.Y[1].PresentSoFar); - gp.LockPlot = gp.X.lock && gp.Y[0].lock && gp.Y[1].lock && gp.Y[2].lock; + gp.LockPlot = gp.X.Lock && gp.Y[0].Lock && gp.Y[1].Lock && gp.Y[2].Lock; // CONSTRAINTS ------------------------------------------------------------ @@ -979,7 +991,7 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons HasFlag(plot.XAxis.Flags, ImPlotAxisFlags_TickLabels)) && plot.XAxis.Divisions > 1; for (int i = 0; i < MAX_Y_AXES; i++) { gp.RenderY[i] = - gp.Y[i].present && + gp.Y[i].Present && (HasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_GridLines) || HasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_TickMarks) || HasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_TickLabels)) && plot.YAxis[i].Divisions > 1; @@ -1000,12 +1012,9 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons float max_label_width[MAX_Y_AXES] = {}; for (int i = 0; i < MAX_Y_AXES; i++) { - if (gp.Y[i].present && HasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_TickLabels)) { + if (gp.Y[i].Present && HasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_TickLabels)) { LabelTicks(gp.YTicks[i], HasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_Scientific), gp.YTickLabels[i]); - for (int t = 0; t < gp.YTicks[i].Size; t++) { - ImPlotTick *yt = &gp.YTicks[i][t]; - max_label_width[i] = yt->Size.x > max_label_width[i] ? yt->Size.x : max_label_width[i]; - } + max_label_width[i] = MaxTickLabelWidth(gp.YTicks[i]); } } @@ -1018,40 +1027,40 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons YPadCalculator y_axis_pad(gp.Y, max_label_width, txt_off); const float pad_left = y_axis_pad(0) + (y_label ? txt_height + txt_off : 0); const float pad_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_Plot = ImRect(gp.BB_Canvas.Min + ImVec2(pad_left, pad_top), gp.BB_Canvas.Max - ImVec2(pad_right, pad_bot)); + gp.Hov_Plot = gp.BB_Plot.Contains(IO.MousePos); // 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)); + const ImRect xAxisRegion_bb(gp.BB_Plot.Min + ImVec2(10, 0), ImVec2(gp.BB_Plot.Max.x, gp.BB_Frame.Max.y) - ImVec2(10, 0)); const bool hov_x_axis_region = xAxisRegion_bb.Contains(IO.MousePos); // The left labels are referenced to the left of the bounding box. - gp.AxisLabelReference[0] = gp.BB_Grid.Min.x; + gp.AxisLabelReference[0] = gp.BB_Plot.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; + gp.AxisLabelReference[1] = gp.BB_Plot.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] = - !gp.Y[1].present ? - gp.BB_Grid.Max.x : + !gp.Y[1].Present ? + gp.BB_Plot.Max.x : (gp.AxisLabelReference[1] + y_axis_pad(1) + 6); ImRect yAxisRegion_bb[MAX_Y_AXES]; - yAxisRegion_bb[0] = ImRect(ImVec2(gp.BB_Frame.Min.x, gp.BB_Grid.Min.y), ImVec2(gp.BB_Grid.Min.x + 6, gp.BB_Grid.Max.y - 10)); + yAxisRegion_bb[0] = ImRect(ImVec2(gp.BB_Frame.Min.x, gp.BB_Plot.Min.y), ImVec2(gp.BB_Plot.Min.x + 6, gp.BB_Plot.Max.y - 10)); // The auxiliary y axes are off to the right of the BB grid. - yAxisRegion_bb[1] = ImRect(ImVec2(gp.BB_Grid.Max.x - 6, gp.BB_Grid.Min.y), - gp.BB_Grid.Max + ImVec2(y_axis_pad(1), 0)); - yAxisRegion_bb[2] = ImRect(ImVec2(gp.AxisLabelReference[2] - 6, gp.BB_Grid.Min.y), + yAxisRegion_bb[1] = ImRect(ImVec2(gp.BB_Plot.Max.x - 6, gp.BB_Plot.Min.y), + gp.BB_Plot.Max + ImVec2(y_axis_pad(1), 0)); + yAxisRegion_bb[2] = ImRect(ImVec2(gp.AxisLabelReference[2] - 6, gp.BB_Plot.Min.y), yAxisRegion_bb[1].Max + ImVec2(y_axis_pad(2), 0)); - ImRect centralRegion(ImVec2(gp.BB_Grid.Min.x + 6, gp.BB_Grid.Min.y), - ImVec2(gp.BB_Grid.Max.x - 6, gp.BB_Grid.Max.y)); + ImRect centralRegion(ImVec2(gp.BB_Plot.Min.x + 6, gp.BB_Plot.Min.y), + ImVec2(gp.BB_Plot.Max.x - 6, gp.BB_Plot.Max.y)); const bool hov_y_axis_region[MAX_Y_AXES] = { - gp.Y[0].present && (yAxisRegion_bb[0].Contains(IO.MousePos) || centralRegion.Contains(IO.MousePos)), - gp.Y[1].present && (yAxisRegion_bb[1].Contains(IO.MousePos) || centralRegion.Contains(IO.MousePos)), - gp.Y[2].present && (yAxisRegion_bb[2].Contains(IO.MousePos) || centralRegion.Contains(IO.MousePos)), + gp.Y[0].Present && (yAxisRegion_bb[0].Contains(IO.MousePos) || centralRegion.Contains(IO.MousePos)), + gp.Y[1].Present && (yAxisRegion_bb[1].Contains(IO.MousePos) || centralRegion.Contains(IO.MousePos)), + gp.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]; @@ -1059,11 +1068,11 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons const bool hov_legend = HasFlag(plot.Flags, ImPlotFlags_Legend) ? gp.Hov_Frame && plot.BB_Legend.Contains(IO.MousePos) : false; bool hov_query = false; - if (gp.Hov_Frame && gp.Hov_Grid && plot.Queried && !plot.Querying) { + if (gp.Hov_Frame && gp.Hov_Plot && plot.Queried && !plot.Querying) { ImRect bb_query = plot.QueryRect; - bb_query.Min += gp.BB_Grid.Min; - bb_query.Max += gp.BB_Grid.Min; + bb_query.Min += gp.BB_Plot.Min; + bb_query.Max += gp.BB_Plot.Min; hov_query = bb_query.Contains(IO.MousePos); } @@ -1077,7 +1086,7 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons plot.QueryRect.Min += IO.MouseDelta; plot.QueryRect.Max += IO.MouseDelta; } - if (gp.Hov_Frame && gp.Hov_Grid && hov_query && !plot.DraggingQuery && !plot.Selecting && !hov_legend) { + if (gp.Hov_Frame && gp.Hov_Plot && hov_query && !plot.DraggingQuery && !plot.Selecting && !hov_legend) { 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) { @@ -1103,33 +1112,33 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons // do drag if (drag_in_progress) { UpdateTransformCache(); - if (!gp.X.lock && plot.XAxis.Dragging) { - ImPlotPoint plot_tl = PixelsToPlot(gp.BB_Grid.Min - IO.MouseDelta, 0); - ImPlotPoint plot_br = PixelsToPlot(gp.BB_Grid.Max - IO.MouseDelta, 0); - if (!gp.X.lock_min) - plot.XAxis.Range.Min = gp.X.invert ? plot_br.x : plot_tl.x; - if (!gp.X.lock_max) - plot.XAxis.Range.Max = gp.X.invert ? plot_tl.x : plot_br.x; + if (!gp.X.Lock && plot.XAxis.Dragging) { + ImPlotPoint plot_tl = PixelsToPlot(gp.BB_Plot.Min - IO.MouseDelta, 0); + ImPlotPoint plot_br = PixelsToPlot(gp.BB_Plot.Max - IO.MouseDelta, 0); + if (!gp.X.LockMin) + plot.XAxis.Range.Min = gp.X.Invert ? plot_br.x : plot_tl.x; + if (!gp.X.LockMax) + plot.XAxis.Range.Max = gp.X.Invert ? plot_tl.x : plot_br.x; } for (int i = 0; i < MAX_Y_AXES; i++) { - if (!gp.Y[i].lock && plot.YAxis[i].Dragging) { - ImPlotPoint plot_tl = PixelsToPlot(gp.BB_Grid.Min - IO.MouseDelta, i); - ImPlotPoint plot_br = PixelsToPlot(gp.BB_Grid.Max - IO.MouseDelta, i); + if (!gp.Y[i].Lock && plot.YAxis[i].Dragging) { + ImPlotPoint plot_tl = PixelsToPlot(gp.BB_Plot.Min - IO.MouseDelta, i); + ImPlotPoint plot_br = PixelsToPlot(gp.BB_Plot.Max - IO.MouseDelta, i); - if (!gp.Y[i].lock_min) - plot.YAxis[i].Range.Min = gp.Y[i].invert ? plot_tl.y : plot_br.y; - if (!gp.Y[i].lock_max) - plot.YAxis[i].Range.Max = gp.Y[i].invert ? plot_br.y : plot_tl.y; + if (!gp.Y[i].LockMin) + plot.YAxis[i].Range.Min = gp.Y[i].Invert ? plot_tl.y : plot_br.y; + if (!gp.Y[i].LockMax) + plot.YAxis[i].Range.Max = gp.Y[i].Invert ? plot_br.y : plot_tl.y; } } // Set the mouse cursor based on which axes are moving. int direction = 0; - if (!gp.X.lock && plot.XAxis.Dragging) { + if (!gp.X.Lock && plot.XAxis.Dragging) { direction |= (1 << 1); } for (int i = 0; i < MAX_Y_AXES; i++) { - if (!gp.Y[i].present) { continue; } - if (!gp.Y[i].lock && plot.YAxis[i].Dragging) { + if (!gp.Y[i].Present) { continue; } + if (!gp.Y[i].Lock && plot.YAxis[i].Dragging) { direction |= (1 << 2); break; } @@ -1164,27 +1173,27 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons 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.0f, 1.0f); - float ty = Remap(IO.MousePos.y, gp.BB_Grid.Min.y, gp.BB_Grid.Max.y, 0.0f, 1.0f); - if (hov_x_axis_region && !gp.X.lock) { + float tx = Remap(IO.MousePos.x, gp.BB_Plot.Min.x, gp.BB_Plot.Max.x, 0.0f, 1.0f); + float ty = Remap(IO.MousePos.y, gp.BB_Plot.Min.y, gp.BB_Plot.Max.y, 0.0f, 1.0f); + if (hov_x_axis_region && !gp.X.Lock) { ImPlotAxisScale axis_scale(0, tx, ty, zoom_rate); const ImPlotPoint& plot_tl = axis_scale.Min; const ImPlotPoint& plot_br = axis_scale.Max; - if (!gp.X.lock_min) - plot.XAxis.Range.Min = gp.X.invert ? plot_br.x : plot_tl.x; - if (!gp.X.lock_max) - plot.XAxis.Range.Max = gp.X.invert ? plot_tl.x : plot_br.x; + if (!gp.X.LockMin) + plot.XAxis.Range.Min = gp.X.Invert ? plot_br.x : plot_tl.x; + if (!gp.X.LockMax) + plot.XAxis.Range.Max = gp.X.Invert ? plot_tl.x : plot_br.x; } for (int i = 0; i < MAX_Y_AXES; i++) { - if (hov_y_axis_region[i] && !gp.Y[i].lock) { + if (hov_y_axis_region[i] && !gp.Y[i].Lock) { ImPlotAxisScale axis_scale(i, tx, ty, zoom_rate); const ImPlotPoint& plot_tl = axis_scale.Min; const ImPlotPoint& plot_br = axis_scale.Max; - if (!gp.Y[i].lock_min) - plot.YAxis[i].Range.Min = gp.Y[i].invert ? plot_tl.y : plot_br.y; - if (!gp.Y[i].lock_max) - plot.YAxis[i].Range.Max = gp.Y[i].invert ? plot_br.y : plot_tl.y; + if (!gp.Y[i].LockMin) + plot.YAxis[i].Range.Min = gp.Y[i].Invert ? plot_tl.y : plot_br.y; + if (!gp.Y[i].LockMax) + plot.YAxis[i].Range.Max = gp.Y[i].Invert ? plot_br.y : plot_tl.y; } } } @@ -1198,16 +1207,16 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons if (HasFlag(plot.Flags, ImPlotFlags_BoxSelect) && ImFabs(select_size.x) > 2 && ImFabs(select_size.y) > 2) { ImPlotPoint p1 = PixelsToPlot(plot.SelectStart); ImPlotPoint p2 = PixelsToPlot(IO.MousePos); - if (!gp.X.lock_min && !IO.KeyAlt) + if (!gp.X.LockMin && !IO.KeyAlt) plot.XAxis.Range.Min = ImMin(p1.x, p2.x); - if (!gp.X.lock_max && !IO.KeyAlt) + if (!gp.X.LockMax && !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 (!gp.Y[i].lock_min && !IO.KeyShift) + if (!gp.Y[i].LockMin && !IO.KeyShift) plot.YAxis[i].Range.Min = ImMin(p1.y, p2.y); - if (!gp.Y[i].lock_max && !IO.KeyShift) + if (!gp.Y[i].LockMax && !IO.KeyShift) plot.YAxis[i].Range.Max = ImMax(p1.y, p2.y); } } @@ -1222,20 +1231,20 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons plot.Selecting = false; } // begin selection or query - if (gp.Hov_Frame && gp.Hov_Grid && IO.MouseClicked[1]) { + if (gp.Hov_Frame && gp.Hov_Plot && IO.MouseClicked[1]) { plot.SelectStart = IO.MousePos; plot.Selecting = true; } // update query if (plot.Querying) { UpdateTransformCache(); - plot.QueryRect.Min.x = IO.KeyAlt ? gp.BB_Grid.Min.x : ImMin(plot.QueryStart.x, IO.MousePos.x); - 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); + plot.QueryRect.Min.x = IO.KeyAlt ? gp.BB_Plot.Min.x : ImMin(plot.QueryStart.x, IO.MousePos.x); + plot.QueryRect.Max.x = IO.KeyAlt ? gp.BB_Plot.Max.x : ImMax(plot.QueryStart.x, IO.MousePos.x); + plot.QueryRect.Min.y = IO.KeyShift ? gp.BB_Plot.Min.y : ImMin(plot.QueryStart.y, IO.MousePos.y); + plot.QueryRect.Max.y = IO.KeyShift ? gp.BB_Plot.Max.y : ImMax(plot.QueryStart.y, IO.MousePos.y); - plot.QueryRect.Min -= gp.BB_Grid.Min; - plot.QueryRect.Max -= gp.BB_Grid.Min; + plot.QueryRect.Min -= gp.BB_Plot.Min; + plot.QueryRect.Max -= gp.BB_Plot.Min; } // end query if (plot.Querying && (IO.MouseReleased[2] || IO.MouseReleased[1])) { @@ -1248,7 +1257,7 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons } } // begin query - if (HasFlag(plot.Flags, ImPlotFlags_Query) && (gp.Hov_Frame && gp.Hov_Grid && IO.MouseClicked[2])) { + if (HasFlag(plot.Flags, ImPlotFlags_Query) && (gp.Hov_Frame && gp.Hov_Plot && IO.MouseClicked[2])) { plot.QueryRect = ImRect(0,0,0,0); plot.Querying = true; plot.Queried = true; @@ -1302,7 +1311,7 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons // RENDER ----------------------------------------------------------------- // grid bg - DrawList.AddRectFilled(gp.BB_Grid.Min, gp.BB_Grid.Max, gp.Col_Bg); + DrawList.AddRectFilled(gp.BB_Plot.Min, gp.BB_Plot.Max, gp.Col_Bg); // render axes PushPlotClipRect(); @@ -1327,15 +1336,15 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons if (HasFlag(plot.XAxis.Flags, ImPlotAxisFlags_GridLines)) { for (int t = 0; t < gp.XTicks.Size; t++) { ImPlotTick *xt = &gp.XTicks[t]; - DrawList.AddLine(ImVec2(xt->PixelPos, gp.BB_Grid.Min.y), ImVec2(xt->PixelPos, gp.BB_Grid.Max.y), xt->Major ? gp.Col_X.Major : gp.Col_X.Minor, 1); + DrawList.AddLine(ImVec2(xt->PixelPos, gp.BB_Plot.Min.y), ImVec2(xt->PixelPos, gp.BB_Plot.Max.y), xt->Major ? gp.Col_X.Major : gp.Col_X.Minor, 1); } } for (int i = 0; i < MAX_Y_AXES; i++) { - if (gp.Y[i].present && HasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_GridLines)) { + if (gp.Y[i].Present && HasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_GridLines)) { for (int t = 0; t < gp.YTicks[i].Size; t++) { ImPlotTick *yt = &gp.YTicks[i][t]; - DrawList.AddLine(ImVec2(gp.BB_Grid.Min.x, yt->PixelPos), ImVec2(gp.BB_Grid.Max.x, yt->PixelPos), yt->Major ? gp.Col_Y[i].Major : gp.Col_Y[i].Minor, 1); + DrawList.AddLine(ImVec2(gp.BB_Plot.Min.x, yt->PixelPos), ImVec2(gp.BB_Plot.Max.x, yt->PixelPos), yt->Major ? gp.Col_Y[i].Major : gp.Col_Y[i].Minor, 1); } } } @@ -1352,28 +1361,24 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons ImGui::PushClipRect(gp.BB_Frame.Min, gp.BB_Frame.Max, true); for (int t = 0; t < gp.XTicks.Size; t++) { ImPlotTick *xt = &gp.XTicks[t]; - if (xt->RenderLabel && xt->PixelPos >= gp.BB_Grid.Min.x - 1 && xt->PixelPos <= gp.BB_Grid.Max.x + 1) - DrawList.AddText(ImVec2(xt->PixelPos - xt->Size.x * 0.5f, gp.BB_Grid.Max.y + txt_off), gp.Col_X.Txt, gp.XTickLabels.Buf.Data + xt->TextOffset); + if (xt->RenderLabel && xt->PixelPos >= gp.BB_Plot.Min.x - 1 && xt->PixelPos <= gp.BB_Plot.Max.x + 1) + DrawList.AddText(ImVec2(xt->PixelPos - xt->Size.x * 0.5f, gp.BB_Plot.Max.y + txt_off), gp.Col_X.Txt, gp.XTickLabels.Buf.Data + xt->TextOffset); } ImGui::PopClipRect(); } if (x_label) { const ImVec2 xLabel_size = ImGui::CalcTextSize(x_label); - const ImVec2 xLabel_pos(gp.BB_Grid.GetCenter().x - xLabel_size.x * 0.5f, + const ImVec2 xLabel_pos(gp.BB_Plot.GetCenter().x - xLabel_size.x * 0.5f, gp.BB_Canvas.Max.y - txt_height); DrawList.AddText(xLabel_pos, gp.Col_X.Txt, x_label); } ImGui::PushClipRect(gp.BB_Frame.Min, gp.BB_Frame.Max, true); for (int i = 0; i < MAX_Y_AXES; i++) { - if (gp.Y[i].present && HasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_TickLabels)) { - const float x_start = - gp.AxisLabelReference[i] + - ((i == 0) ? - (-txt_off - max_label_width[0]) : - txt_off); + if (gp.Y[i].Present && HasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_TickLabels)) { for (int t = 0; t < gp.YTicks[i].Size; t++) { + const float x_start = gp.AxisLabelReference[i] + (i == 0 ? (-txt_off - gp.YTicks[i][t].Size.x) : txt_off); ImPlotTick *yt = &gp.YTicks[i][t]; - if (yt->RenderLabel && yt->PixelPos >= gp.BB_Grid.Min.y - 1 && yt->PixelPos <= gp.BB_Grid.Max.y + 1) { + if (yt->RenderLabel && yt->PixelPos >= gp.BB_Plot.Min.y - 1 && yt->PixelPos <= gp.BB_Plot.Max.y + 1) { ImVec2 start(x_start, yt->PixelPos - 0.5f * yt->Size.y); DrawList.AddText(start, gp.Col_Y[i].Txt, gp.YTickLabels[i].Buf.Data + yt->TextOffset); } @@ -1383,7 +1388,7 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons 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); + const ImVec2 yLabel_pos(gp.BB_Canvas.Min.x, gp.BB_Plot.GetCenter().y + yLabel_size.y * 0.5f); AddTextVertical(&DrawList, y_label, yLabel_pos, gp.Col_Y[0].Txt); } @@ -1427,54 +1432,54 @@ inline void EndDisabledControls(bool cond) { } } -inline void AxisMenu(ImPlotAxis& Axis, ImPlotAxisState& state) { +inline void AxisMenu(ImPlotAxisState& state) { ImGui::PushItemWidth(75); - bool total_lock = state.has_range && state.range_cond == ImGuiCond_Always; - bool logscale = HasFlag(Axis.Flags, ImPlotAxisFlags_LogScale); - bool grid = HasFlag(Axis.Flags, ImPlotAxisFlags_GridLines); - bool ticks = HasFlag(Axis.Flags, ImPlotAxisFlags_TickMarks); - bool labels = HasFlag(Axis.Flags, ImPlotAxisFlags_TickLabels); + bool total_lock = state.HasRange && state.RangeCond == ImGuiCond_Always; + bool logscale = HasFlag(state.Axis->Flags, ImPlotAxisFlags_LogScale); + bool grid = HasFlag(state.Axis->Flags, ImPlotAxisFlags_GridLines); + bool ticks = HasFlag(state.Axis->Flags, ImPlotAxisFlags_TickMarks); + bool labels = HasFlag(state.Axis->Flags, ImPlotAxisFlags_TickLabels); BeginDisabledControls(total_lock); - if (ImGui::Checkbox("##LockMin", &state.lock_min)) - FlipFlag(Axis.Flags, ImPlotAxisFlags_LockMin); + if (ImGui::Checkbox("##LockMin", &state.LockMin)) + FlipFlag(state.Axis->Flags, ImPlotAxisFlags_LockMin); EndDisabledControls(total_lock); ImGui::SameLine(); - BeginDisabledControls(state.lock_min); - DragFloat("Min", &Axis.Range.Min, 0.01f + 0.01f * (float)Axis.Range.Size(), -HUGE_VAL, Axis.Range.Max - DBL_EPSILON); - EndDisabledControls(state.lock_min); + BeginDisabledControls(state.LockMin); + DragFloat("Min", &state.Axis->Range.Min, 0.01f * (float)state.Axis->Range.Size(), -HUGE_VAL, state.Axis->Range.Max - DBL_EPSILON); + EndDisabledControls(state.LockMin); BeginDisabledControls(total_lock); - if (ImGui::Checkbox("##LockMax", &state.lock_max)) - FlipFlag(Axis.Flags, ImPlotAxisFlags_LockMax); + if (ImGui::Checkbox("##LockMax", &state.LockMax)) + FlipFlag(state.Axis->Flags, ImPlotAxisFlags_LockMax); EndDisabledControls(total_lock); ImGui::SameLine(); - BeginDisabledControls(state.lock_max); - DragFloat("Max", &Axis.Range.Max, 0.01f + 0.01f * (float)Axis.Range.Size(), Axis.Range.Min + DBL_EPSILON, HUGE_VAL); - EndDisabledControls(state.lock_max); + BeginDisabledControls(state.LockMax); + DragFloat("Max", &state.Axis->Range.Max, 0.01f * (float)state.Axis->Range.Size(), state.Axis->Range.Min + DBL_EPSILON, HUGE_VAL); + EndDisabledControls(state.LockMax); ImGui::Separator(); - if (ImGui::Checkbox("Invert", &state.invert)) - FlipFlag(Axis.Flags, ImPlotAxisFlags_Invert); + if (ImGui::Checkbox("Invert", &state.Invert)) + FlipFlag(state.Axis->Flags, ImPlotAxisFlags_Invert); if (ImGui::Checkbox("Log Scale", &logscale)) - FlipFlag(Axis.Flags, ImPlotAxisFlags_LogScale); + FlipFlag(state.Axis->Flags, ImPlotAxisFlags_LogScale); ImGui::Separator(); if (ImGui::Checkbox("Grid Lines", &grid)) - FlipFlag(Axis.Flags, ImPlotAxisFlags_GridLines); + FlipFlag(state.Axis->Flags, ImPlotAxisFlags_GridLines); if (ImGui::Checkbox("Tick Marks", &ticks)) - FlipFlag(Axis.Flags, ImPlotAxisFlags_TickMarks); + FlipFlag(state.Axis->Flags, ImPlotAxisFlags_TickMarks); if (ImGui::Checkbox("Labels", &labels)) - FlipFlag(Axis.Flags, ImPlotAxisFlags_TickLabels); + FlipFlag(state.Axis->Flags, ImPlotAxisFlags_TickLabels); } void PlotContextMenu(ImPlotState& plot) { if (ImGui::BeginMenu("X-Axis")) { ImGui::PushID("X"); - AxisMenu(plot.XAxis, gp.X); + AxisMenu(gp.X); ImGui::PopID(); ImGui::EndMenu(); } @@ -1493,7 +1498,7 @@ void PlotContextMenu(ImPlotState& plot) { } if (ImGui::BeginMenu(buf)) { ImGui::PushID(i); - AxisMenu(plot.YAxis[i], gp.Y[i]); + AxisMenu(gp.Y[i]); ImGui::PopID(); ImGui::EndMenu(); } @@ -1578,7 +1583,7 @@ void EndPlot() { // AXIS STATES ------------------------------------------------------------ - const bool any_y_locked = gp.Y[0].lock || gp.Y[1].present ? gp.Y[1].lock : false || gp.Y[2].present ? gp.Y[2].lock : false; + const bool any_y_locked = gp.Y[0].Lock || gp.Y[1].Present ? gp.Y[1].Lock : false || gp.Y[2].Present ? gp.Y[2].Lock : false; const bool any_y_dragging = plot.YAxis[0].Dragging || plot.YAxis[1].Dragging || plot.YAxis[2].Dragging; @@ -1589,15 +1594,15 @@ void EndPlot() { if (HasFlag(plot.XAxis.Flags, ImPlotAxisFlags_TickMarks)) { for (int t = 0; t < gp.XTicks.Size; t++) { ImPlotTick *xt = &gp.XTicks[t]; - DrawList.AddLine(ImVec2(xt->PixelPos, gp.BB_Grid.Max.y),ImVec2(xt->PixelPos, gp.BB_Grid.Max.y - (xt->Major ? 10.0f : 5.0f)), gp.Col_Border, 1); + DrawList.AddLine(ImVec2(xt->PixelPos, gp.BB_Plot.Max.y),ImVec2(xt->PixelPos, gp.BB_Plot.Max.y - (xt->Major ? 10.0f : 5.0f)), gp.Col_Border, 1); } } PopPlotClipRect(); - ImGui::PushClipRect(gp.BB_Grid.Min, ImVec2(gp.BB_Frame.Max.x, gp.BB_Grid.Max.y), true); + ImGui::PushClipRect(gp.BB_Plot.Min, ImVec2(gp.BB_Frame.Max.x, gp.BB_Plot.Max.y), true); int axis_count = 0; for (int i = 0; i < MAX_Y_AXES; i++) { - if (!gp.Y[i].present) { continue; } + if (!gp.Y[i].Present) { continue; } axis_count++; if (!HasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_TickMarks)) { continue; } @@ -1619,8 +1624,8 @@ void EndPlot() { 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), + ImVec2(x_start, gp.BB_Plot.Min.y), + ImVec2(x_start, gp.BB_Plot.Max.y), gp.Col_Border, 1); } } @@ -1633,16 +1638,16 @@ void EndPlot() { bool select_big_enough = ImLengthSqr(select_bb.GetSize()) > 4; if (plot.Selecting && !gp.LockPlot && HasFlag(plot.Flags, ImPlotFlags_BoxSelect) && select_big_enough) { if (IO.KeyAlt && IO.KeyShift) { - 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); + DrawList.AddRectFilled(gp.BB_Plot.Min, gp.BB_Plot.Max, gp.Col_SlctBg); + DrawList.AddRect( gp.BB_Plot.Min, gp.BB_Plot.Max, gp.Col_SlctBd); } - else if ((gp.X.lock || IO.KeyAlt)) { - 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 ((gp.X.Lock || IO.KeyAlt)) { + DrawList.AddRectFilled(ImVec2(gp.BB_Plot.Min.x, select_bb.Min.y), ImVec2(gp.BB_Plot.Max.x, select_bb.Max.y), gp.Col_SlctBg); + DrawList.AddRect( ImVec2(gp.BB_Plot.Min.x, select_bb.Min.y), ImVec2(gp.BB_Plot.Max.x, select_bb.Max.y), gp.Col_SlctBd); } else if ((any_y_locked || IO.KeyShift)) { - 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); + DrawList.AddRectFilled(ImVec2(select_bb.Min.x, gp.BB_Plot.Min.y), ImVec2(select_bb.Max.x, gp.BB_Plot.Max.y), gp.Col_SlctBg); + DrawList.AddRect( ImVec2(select_bb.Min.x, gp.BB_Plot.Min.y), ImVec2(select_bb.Max.x, gp.BB_Plot.Max.y), gp.Col_SlctBd); } else { DrawList.AddRectFilled(select_bb.Min, select_bb.Max, gp.Col_SlctBg); @@ -1653,15 +1658,15 @@ void EndPlot() { 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); + DrawList.AddRectFilled(plot.QueryRect.Min + gp.BB_Plot.Min, plot.QueryRect.Max + gp.BB_Plot.Min, gp.Col_QryBg); + DrawList.AddRect( plot.QueryRect.Min + gp.BB_Plot.Min, plot.QueryRect.Max + gp.BB_Plot.Min, gp.Col_QryBd); } } else if (plot.Queried) { ImRect bb_query = plot.QueryRect; - bb_query.Min += gp.BB_Grid.Min; - bb_query.Max += gp.BB_Grid.Min; + bb_query.Min += gp.BB_Plot.Min; + bb_query.Max += gp.BB_Plot.Min; DrawList.AddRectFilled(bb_query.Min, bb_query.Max, gp.Col_QryBg); DrawList.AddRect( bb_query.Min, bb_query.Max, gp.Col_QryBd); @@ -1683,7 +1688,7 @@ void EndPlot() { 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)); + legend_content_bb = ImRect(gp.BB_Plot.Min + legend_offset, gp.BB_Plot.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 @@ -1728,18 +1733,18 @@ void EndPlot() { } // render crosshairs - if (HasFlag(plot.Flags, ImPlotFlags_Crosshairs) && gp.Hov_Grid && gp.Hov_Frame && + if (HasFlag(plot.Flags, ImPlotFlags_Crosshairs) && gp.Hov_Plot && gp.Hov_Frame && !(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); + ImVec2 h1(gp.BB_Plot.Min.x, xy.y); ImVec2 h2(xy.x - 5, xy.y); ImVec2 h3(xy.x + 5, xy.y); - ImVec2 h4(gp.BB_Grid.Max.x, xy.y); - ImVec2 v1(xy.x, gp.BB_Grid.Min.y); + ImVec2 h4(gp.BB_Plot.Max.x, xy.y); + ImVec2 v1(xy.x, gp.BB_Plot.Min.y); ImVec2 v2(xy.x, xy.y - 5); ImVec2 v3(xy.x, xy.y + 5); - ImVec2 v4(xy.x, gp.BB_Grid.Max.y); + ImVec2 v4(xy.x, gp.BB_Plot.Max.y); DrawList.AddLine(h1, h2, gp.Col_Border); DrawList.AddLine(h3, h4, gp.Col_Border); DrawList.AddLine(v1, v2, gp.Col_Border); @@ -1747,7 +1752,7 @@ void EndPlot() { } // render mouse pos - if (HasFlag(plot.Flags, ImPlotFlags_MousePos) && gp.Hov_Grid) { + if (HasFlag(plot.Flags, ImPlotFlags_MousePos) && gp.Hov_Plot) { char buffer[128] = {}; BufferWriter writer(buffer, sizeof(buffer)); @@ -1759,14 +1764,14 @@ void EndPlot() { writer.Write(",(%.2f)", gp.LastMousePos[2].y); } ImVec2 size = ImGui::CalcTextSize(buffer); - ImVec2 pos = gp.BB_Grid.Max - size - ImVec2(5, 5); + ImVec2 pos = gp.BB_Plot.Max - size - ImVec2(5, 5); DrawList.AddText(pos, gp.Col_Txt, buffer); } PopPlotClipRect(); // render border - DrawList.AddRect(gp.BB_Grid.Min, gp.BB_Grid.Max, gp.Col_Border); + DrawList.AddRect(gp.BB_Plot.Min, gp.BB_Plot.Max, gp.Col_Border); // FIT DATA -------------------------------------------------------------- @@ -1789,7 +1794,7 @@ void EndPlot() { // CONTEXT MENU ----------------------------------------------------------- - if (HasFlag(plot.Flags, ImPlotFlags_ContextMenu) && gp.Hov_Frame && gp.Hov_Grid && IO.MouseDoubleClicked[1] && !hov_legend) + if (HasFlag(plot.Flags, ImPlotFlags_ContextMenu) && gp.Hov_Frame && gp.Hov_Plot && IO.MouseDoubleClicked[1] && !hov_legend) ImGui::OpenPopup("##Context"); if (ImGui::BeginPopup("##Context")) { PlotContextMenu(plot); @@ -1867,17 +1872,17 @@ void SetPlotYAxis(int y_axis) { ImVec2 GetPlotPos() { IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "GetPlotPos() needs to be called between BeginPlot() and EndPlot()!"); - return gp.BB_Grid.Min; + return gp.BB_Plot.Min; } ImVec2 GetPlotSize() { IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "GetPlotSize() needs to be called between BeginPlot() and EndPlot()!"); - return gp.BB_Grid.GetSize(); + return gp.BB_Plot.GetSize(); } void PushPlotClipRect() { IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "PushPlotClipRect() needs to be called between BeginPlot() and EndPlot()!"); - ImGui::PushClipRect(gp.BB_Grid.Min, gp.BB_Grid.Max, true); + ImGui::PushClipRect(gp.BB_Plot.Min, gp.BB_Plot.Max, true); } void PopPlotClipRect() { @@ -1886,7 +1891,7 @@ void PopPlotClipRect() { bool IsPlotHovered() { IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "IsPlotHovered() needs to be called between BeginPlot() and EndPlot()!"); - return gp.Hov_Grid; + return gp.Hov_Plot; } ImPlotPoint 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"); @@ -1920,8 +1925,8 @@ ImPlotLimits GetPlotQuery(int y_axis_in) { const int y_axis = y_axis_in >= 0 ? y_axis_in : gp.CurrentPlot->CurrentYAxis; UpdateTransformCache(); - ImPlotPoint p1 = PixelsToPlot(plot.QueryRect.Min + gp.BB_Grid.Min, y_axis); - ImPlotPoint p2 = PixelsToPlot(plot.QueryRect.Max + gp.BB_Grid.Min, y_axis); + ImPlotPoint p1 = PixelsToPlot(plot.QueryRect.Min + gp.BB_Plot.Min, y_axis); + ImPlotPoint p2 = PixelsToPlot(plot.QueryRect.Max + gp.BB_Plot.Min, y_axis); ImPlotLimits result; result.X.Min = ImMin(p1.x, p2.x); @@ -2136,7 +2141,7 @@ int idx = offset; ImVec2 c; c = transformer(getter(idx)); idx = (idx + 1) % count; - if (!cull || gp.BB_Grid.Contains(c)) { + if (!cull || gp.BB_Plot.Contains(c)) { // TODO: Optimize the loop and if statements, this is atrocious if (HasFlag(gp.Style.Marker, ImPlotMarker_Circle)) MarkerCircle(DrawList, c, gp.Style.MarkerSize, rend_mk_line, col_mk_line, rend_mk_fill, col_mk_fill, gp.Style.MarkerWeight); @@ -2274,7 +2279,7 @@ inline void RenderLineStrip(Getter getter, Transformer transformer, ImDrawList& for (int i1 = i_start; i1 != i_end; i1 = i1 + 1 < count ? i1 + 1 : i1 + 1 - count) { ImVec2 p2 = transformer(getter(i1)); - if (!cull || gp.BB_Grid.Overlaps(ImRect(ImMin(p1, p2), ImMax(p1, p2)))) + if (!cull || gp.BB_Plot.Overlaps(ImRect(ImMin(p1, p2), ImMax(p1, p2)))) RenderLineAA(DrawList, p1, p2, line_weight, col_line); p1 = p2; } @@ -2285,7 +2290,7 @@ inline void RenderLineStrip(Getter getter, Transformer transformer, ImDrawList& int segments_culled = 0; for (int i1 = i_start; i1 != i_end; i1 = i1 + 1 < count ? i1 + 1 : i1 + 1 - count) { ImVec2 p2 = transformer(getter(i1)); - if (!cull || gp.BB_Grid.Overlaps(ImRect(ImMin(p1, p2), ImMax(p1, p2)))) + if (!cull || gp.BB_Plot.Overlaps(ImRect(ImMin(p1, p2), ImMax(p1, p2)))) RenderLine(DrawList, p1, p2, line_weight, col_line, uv); else segments_culled++; @@ -2872,7 +2877,7 @@ inline void DrawPieSlice(ImDrawList& DrawList, const ImPlotPoint& center, double } template -void PlotPieChartEx(const char** label_ids, T* values, int count, T x, T y, T radius, const char* fmt, T angle0) { +void PlotPieChartEx(const char** label_ids, const T* values, int count, T x, T y, T radius, bool normalize, const char* fmt, T angle0) { IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "PlotPieChart() needs to be called between BeginPlot() and EndPlot()!"); ImDrawList & DrawList = *ImGui::GetWindowDrawList(); @@ -2880,7 +2885,7 @@ void PlotPieChartEx(const char** label_ids, T* values, int count, T x, T y, T ra for (int i = 0; i < count; ++i) sum += values[i]; - const bool normalize = sum > 1.0f; + normalize = normalize || sum > 1.0f; ImPlotPoint center(x,y); @@ -2900,33 +2905,40 @@ void PlotPieChartEx(const char** label_ids, T* values, int count, T x, T y, T ra DrawPieSlice(DrawList, center, radius, a0, a0 + (a1 - a0) * 0.5f, col); DrawPieSlice(DrawList, center, radius, a0 + (a1 - a0) * 0.5f, a1, col); } - if (fmt != NULL) { - char buffer[32]; - sprintf(buffer, fmt, percent * 100); - ImVec2 size = ImGui::CalcTextSize(buffer); - T angle = a0 + (a1 - a0) * 0.5f; - ImVec2 pos = PlotToPixels(center.x + 0.5f * radius * cos(angle), center.y + 0.5f * radius * sin(angle)); - 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; } + if (fmt != NULL) { + a0 = angle0 * 2 * IM_PI / 360.0f; + a1 = angle0 * 2 * IM_PI / 360.0f; + char buffer[32]; + for (int i = 0; i < count; ++i) { + T percent = normalize ? values[i] / sum : values[i]; + a1 = a0 + 2 * IM_PI * percent; + sprintf(buffer, fmt, values[i]); + ImVec2 size = ImGui::CalcTextSize(buffer); + T angle = a0 + (a1 - a0) * 0.5f; + ImVec2 pos = PlotToPixels(center.x + 0.5f * radius * cos(angle), center.y + 0.5f * radius * sin(angle)); + 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; + } + } PopPlotClipRect(); } //----------------------------------------------------------------------------- // float -void PlotPieChart(const char** label_ids, float* values, int count, float x, float y, float radius, const char* fmt, float angle0) { - return PlotPieChartEx(label_ids, values, count, x, y, radius, fmt, angle0); +void PlotPieChart(const char** label_ids, const float* values, int count, float x, float y, float radius, bool normalize, const char* fmt, float angle0) { + return PlotPieChartEx(label_ids, values, count, x, y, radius, normalize, fmt, angle0); } //----------------------------------------------------------------------------- // double -void PlotPieChart(const char** label_ids, double* values, int count, double x, double y, double radius, const char* fmt, double angle0) { - return PlotPieChartEx(label_ids, values, count, x, y, radius, fmt, angle0); +void PlotPieChart(const char** label_ids, const double* values, int count, double x, double y, double radius, bool normalize, const char* fmt, double angle0) { + return PlotPieChartEx(label_ids, values, count, x, y, radius, normalize, fmt, angle0); } //----------------------------------------------------------------------------- @@ -2987,7 +2999,7 @@ void PlotHeatmapEx(const char* label_id, const T* values, int rows, int cols, T FitPoint(bounds_max); } ImDrawList& DrawList = *ImGui::GetWindowDrawList(); - ImGui::PushClipRect(gp.BB_Grid.Min, gp.BB_Grid.Max, true); + ImGui::PushClipRect(gp.BB_Plot.Min, gp.BB_Plot.Max, true); ImPlotState* plot = gp.CurrentPlot; int y_axis = plot->CurrentYAxis; if (HasFlag(plot->XAxis.Flags, ImPlotAxisFlags_LogScale) && HasFlag(plot->YAxis[y_axis].Flags, ImPlotAxisFlags_LogScale)) @@ -3035,7 +3047,7 @@ inline void PlotDigitalEx(const char* label_id, Getter getter, int count, int of if (gp.Style.Colors[ImPlotCol_Line].w != -1) item->Color = gp.Style.Colors[ImPlotCol_Line]; - ImGui::PushClipRect(gp.BB_Grid.Min, gp.BB_Grid.Max, true); + ImGui::PushClipRect(gp.BB_Plot.Min, gp.BB_Plot.Max, true); bool cull = HasFlag(gp.CurrentPlot->Flags, ImPlotFlags_CullData); const float line_weight = item->Highlight ? gp.Style.LineWeight * 2 : gp.Style.LineWeight; @@ -3079,7 +3091,7 @@ inline void PlotDigitalEx(const char* label_id, Getter getter, int count, int of 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))) { + if ((pMax.x > pMin.x) && (!cull || gp.BB_Plot.Contains(pMin) || gp.BB_Plot.Contains(pMax))) { ImVec4 colAlpha = item->Color; colAlpha.w = item->Highlight ? 1.0f : 0.9f; DrawList.AddRectFilled(pMin, pMax, ImGui::GetColorU32(colAlpha)); @@ -3159,7 +3171,7 @@ int GetColormapSize() { return gp.ColormapSize; } -/// Returns a color from the Color map given an index > 0 +// Returns a color from the Color map given an index > 0 ImVec4 GetColormapColor(int index) { IM_ASSERT_USER_ERROR(index >= 0, "The Colormap index must be greater than zero!"); return gp.Colormap[index % gp.ColormapSize]; diff --git a/implot.h b/implot.h index 1970e56..6f5e60e 100644 --- a/implot.h +++ b/implot.h @@ -160,15 +160,15 @@ struct ImPlotLimits { // Plot style structure struct ImPlotStyle { - float LineWeight; // = 1, line weight in pixels - ImPlotMarker Marker; // = ImPlotMarker_None, marker specification - float MarkerSize; // = 4, marker size in pixels (roughly the marker's "radius") - 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 - 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 + float LineWeight; // = 1, line weight in pixels + ImPlotMarker Marker; // = ImPlotMarker_None, marker specification + float MarkerSize; // = 4, marker size in pixels (roughly the marker's "radius") + 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 + 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(); }; @@ -238,9 +238,9 @@ void PlotErrorBars(const char* label_id, const double* xs, const double* ys, con 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, const double* xs, const double* ys, const double* neg, const double* pos, int count, int offset = 0, int stride = sizeof(double)); -// 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, float x, float y, float radius, const char* label_fmt = "%.1f%%", float angle0 = 90); -void PlotPieChart(const char** label_ids, double* values, int count, double x, double y, double radius, const char* label_fmt = "%.1f%%", double angle0 = 90); +// Plots a pie chart. If the sum of values > 1 or normalize is true, each value will be normalized. Center and radius are in plot coordinates. +void PlotPieChart(const char** label_ids, const float* values, int count, float x, float y, float radius, bool normalize = false, const char* label_fmt = "%.1f", float angle0 = 90); +void PlotPieChart(const char** label_ids, const double* values, int count, double x, double y, double radius, bool normalize = false, const char* label_fmt = "%.1f", double angle0 = 90); // Plots a 2D heatmap chart. Values are expected to be in row-major order. label_fmt can be set to NULL for no labels. void PlotHeatmap(const char* label_id, const float* values, int rows, int cols, float scale_min, float scale_max, const char* label_fmt = "%.1f", const ImPlotPoint& bounds_min = ImPlotPoint(0,0), const ImPlotPoint& bounds_max = ImPlotPoint(1,1)); @@ -297,7 +297,7 @@ void SetColormap(ImPlotColormap colormap, int samples = 0); void SetColormap(const ImVec4* colors, int num_colors); // Returns the size of the current colormap int GetColormapSize(); -/// Returns a color from the Color map given an index > 0 (modulo will be performed) +// Returns a color from the Color map given an index > 0 (modulo will be performed) ImVec4 GetColormapColor(int index); // Linearly interpolates a color from the current colormap given t between 0 and 1. ImVec4 LerpColormap(float t); diff --git a/implot_demo.cpp b/implot_demo.cpp index 1523037..af5a07d 100644 --- a/implot_demo.cpp +++ b/implot_demo.cpp @@ -295,20 +295,26 @@ void ShowDemoWindow(bool* p_open) { //------------------------------------------------------------------------- if (ImGui::CollapsingHeader("Pie Charts")) { static const char* labels1[] = {"Frogs","Hogs","Dogs","Logs"}; - static t_float pre_normalized[] = {0.15f, 0.30f, 0.45f, 0.10f}; - + static float data1[] = {0.15f, 0.30f, 0.2f, 0.05f}; + static bool normalize = false; + ImGui::SetNextItemWidth(250); + ImGui::DragFloat4("Values", data1, 0.01f, 0, 1); + if ((data1[0] + data1[1] + data1[2] + data1[3]) < 1) { + ImGui::SameLine(); + ImGui::Checkbox("Normalize", &normalize); + } SetNextPlotLimits(0,1,0,1,ImGuiCond_Always); if (ImPlot::BeginPlot("##Pie1", NULL, NULL, ImVec2(250,250), ImPlotFlags_Legend, 0, 0)) { - ImPlot::PlotPieChart(labels1, pre_normalized, 4, 0.5f, 0.5f, 0.4f); + ImPlot::PlotPieChart(labels1, data1, 4, 0.5f, 0.5f, 0.4f, normalize, "%.2f"); ImPlot::EndPlot(); } ImGui::SameLine(); ImPlot::SetColormap(ImPlotColormap_Cool, 5); SetNextPlotLimits(0,1,0,1,ImGuiCond_Always); - static const char* labels2[] = {"One##1","One##2","Two","Three","Five"}; - static t_float not_normalized[] = {1,1,2,3,5}; + static const char* labels2[] = {"A","B","C","D","E"}; + static t_float data2[] = {1,1,2,3,5}; if (ImPlot::BeginPlot("##Pie2", NULL, NULL, ImVec2(250,250), ImPlotFlags_Legend, 0, 0)) { - ImPlot::PlotPieChart(labels2, not_normalized, 5, 0.5f, 0.5f, 0.4f, NULL, 0); + ImPlot::PlotPieChart(labels2, data2, 5, 0.5f, 0.5f, 0.4f, true, "%.0f", 180); ImPlot::EndPlot(); } ImPlot::SetColormap(ImPlotColormap_Default); From 523ae3aef482eca044aa904ed02fc61763ecc3cd Mon Sep 17 00:00:00 2001 From: Evan Pezent Date: Sat, 6 Jun 2020 17:54:46 -0500 Subject: [PATCH 5/5] fixed dragging issue where plots that were not mouse-clicked would be dragged --- implot.cpp | 24 ++++++++++++++---------- implot_demo.cpp | 1 - 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/implot.cpp b/implot.cpp index f242d39..85a5c2d 100644 --- a/implot.cpp +++ b/implot.cpp @@ -1143,19 +1143,23 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons break; } } - - if (direction == 0) { - ImGui::SetMouseCursor(ImGuiMouseCursor_NotAllowed); - } else if (direction == (1 << 1)) { - ImGui::SetMouseCursor(ImGuiMouseCursor_ResizeEW); - } else if (direction == (1 << 2)) { - ImGui::SetMouseCursor(ImGuiMouseCursor_ResizeNS); - } else { - ImGui::SetMouseCursor(ImGuiMouseCursor_ResizeAll); + if (IO.MouseDragMaxDistanceSqr[0] > 5) { + if (direction == 0) { + ImGui::SetMouseCursor(ImGuiMouseCursor_NotAllowed); + } + else if (direction == (1 << 1)) { + ImGui::SetMouseCursor(ImGuiMouseCursor_ResizeEW); + } + else if (direction == (1 << 2)) { + ImGui::SetMouseCursor(ImGuiMouseCursor_ResizeNS); + } + else { + ImGui::SetMouseCursor(ImGuiMouseCursor_ResizeAll); + } } } // start drag - if (!drag_in_progress && gp.Hov_Frame && IO.MouseDragMaxDistanceSqr[0] > 5 && !plot.Selecting && !hov_legend && !hov_query && !plot.DraggingQuery) { + if (!drag_in_progress && gp.Hov_Frame && IO.MouseClicked[0] && !plot.Selecting && !hov_legend && !hov_query && !plot.DraggingQuery) { if (hov_x_axis_region) { plot.XAxis.Dragging = true; } diff --git a/implot_demo.cpp b/implot_demo.cpp index 95c0e65..3231854 100644 --- a/implot_demo.cpp +++ b/implot_demo.cpp @@ -921,7 +921,6 @@ void ShowDemoWindow(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); - SetNextPlotLimits(0,1,0,1, ImGuiCond_Always); if (ImPlot::BeginPlot("##Bench",NULL,NULL,ImVec2(-1,0),ImPlotFlags_Default | ImPlotFlags_NoChild)) { char buff[16]; for (int i = 0; i < 100; ++i) {