From 13927c608dd6fe0da1ac1563357ccbb3b316ac37 Mon Sep 17 00:00:00 2001 From: epezent Date: Thu, 17 Sep 2020 09:58:33 -0500 Subject: [PATCH] add public API for horizontal and vertical guide lines --- implot.cpp | 64 ++++++++++++++++++++++++++++++++++++++++++++++++- implot.h | 5 ++++ implot_demo.cpp | 49 +++++++++++++------------------------ 3 files changed, 85 insertions(+), 33 deletions(-) diff --git a/implot.cpp b/implot.cpp index b57946a..be01ae9 100644 --- a/implot.cpp +++ b/implot.cpp @@ -1185,7 +1185,7 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons // capture scroll with a child region if (!ImHasFlag(plot.Flags, ImPlotFlags_NoChild)) { - ImGui::BeginChild(title, ImVec2(size.x == 0 ? IMPLOT_DEFAULT_W : size.x, size.y == 0 ? IMPLOT_DEFAULT_H : size.y)); + ImGui::BeginChild(title, ImVec2(size.x == 0 ? IMPLOT_DEFAULT_W : size.x, size.y == 0 ? IMPLOT_DEFAULT_H : size.y), false, ImGuiWindowFlags_NoScrollbar); Window = ImGui::GetCurrentWindow(); Window->ScrollMax.y = 1.0f; gp.ChildWindowMade = true; @@ -2479,6 +2479,68 @@ ImPlotLimits GetPlotQuery(int y_axis_in) { return result; } +bool HorizontalGuide(const char* id, double* value, const ImVec4& col, float thickness) { + ImPlotContext& gp = *GImPlot; + IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "HorizontalGuide() needs to be called between BeginPlot() and EndPlot()!"); + const float grab_size = 2*thickness; + float xl = gp.BB_Plot.Min.x; + float xr = gp.BB_Plot.Max.x; + float y = PlotToPixels(0, *value).y; + ImU32 col32 = IsColorAuto(col) ? GetStyleColorU32(ImPlotCol_Query) : ImGui::ColorConvertFloat4ToU32(col); + PushPlotClipRect(); + GetPlotDrawList()->AddLine(ImVec2(xl,y), ImVec2(xr,y), col32, thickness); + PopPlotClipRect(); + const bool outside = (y < gp.BB_Plot.Min.y - grab_size / 2 || y > gp.BB_Plot.Max.y + grab_size / 2); + if (outside) + return false; + ImVec2 old_cursor_pos = ImGui::GetCursorScreenPos(); + ImVec2 new_cursor_pos = ImVec2(xl, y - grab_size / 2.0f); + ImGui::SetItemAllowOverlap(); + ImGui::SetCursorScreenPos(new_cursor_pos); + ImGui::InvisibleButton(id, ImVec2(xr - xl, grab_size)); + ImGui::SetCursorScreenPos(old_cursor_pos); + if (ImGui::IsItemHovered() || ImGui::IsItemActive()) { + ImGui::SetMouseCursor(ImGuiMouseCursor_ResizeNS); + } + bool dragging = false; + if (ImGui::IsItemActive() && ImGui::IsMouseDragging(0)) { + *value = ImPlot::GetPlotMousePos().y; + dragging = true; + } + return dragging; +} + +bool VerticalGuide(const char* id, double* value, const ImVec4& col, float thickness) { + ImPlotContext& gp = *GImPlot; + IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "VerticalGuide() needs to be called between BeginPlot() and EndPlot()!"); + const float grab_size = 2*thickness; + float yt = gp.BB_Plot.Min.y; + float yb = gp.BB_Plot.Max.y; + float x = PlotToPixels(*value,0).x; + ImU32 col32 = IsColorAuto(col) ? GetStyleColorU32(ImPlotCol_Query) : ImGui::ColorConvertFloat4ToU32(col); + PushPlotClipRect(); + GetPlotDrawList()->AddLine(ImVec2(x,yt), ImVec2(x,yb), col32, thickness); + PopPlotClipRect(); + const bool outside = (x < gp.BB_Plot.Min.x - grab_size / 2 || x > gp.BB_Plot.Max.x + grab_size / 2); + if (outside) + return false; + ImVec2 old_cursor_pos = ImGui::GetCursorScreenPos(); + ImVec2 new_cursor_pos = ImVec2(x - grab_size / 2.0f, yt); + ImGui::SetItemAllowOverlap(); + ImGui::SetCursorScreenPos(new_cursor_pos); + ImGui::InvisibleButton(id, ImVec2(grab_size, yb-yt)); + ImGui::SetCursorScreenPos(old_cursor_pos); + if (ImGui::IsItemHovered() || ImGui::IsItemActive()) { + ImGui::SetMouseCursor(ImGuiMouseCursor_ResizeEW); + } + bool dragging = false; + if (ImGui::IsItemActive() && ImGui::IsMouseDragging(0)) { + *value = ImPlot::GetPlotMousePos().x; + dragging = true; + } + return dragging; +} + bool IsLegendEntryHovered(const char* label_id) { ImPlotContext& gp = *GImPlot; IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "IsPlotItemHighlight() needs to be called between BeginPlot() and EndPlot()!"); diff --git a/implot.h b/implot.h index cf2274e..b51a29f 100644 --- a/implot.h +++ b/implot.h @@ -459,6 +459,11 @@ IMPLOT_API bool IsPlotQueried(); // Returns the current plot query bounds. IMPLOT_API ImPlotLimits GetPlotQuery(int y_axis = IMPLOT_AUTO); +// Shows a draggable horizontal guide line. +IMPLOT_API bool HorizontalGuide(const char* id, double* value, const ImVec4& col = IMPLOT_AUTO_COL, float thickness = 2); +// Shows a draggable vertical guide line. +IMPLOT_API bool VerticalGuide(const char* id, double* value, const ImVec4& col = IMPLOT_AUTO_COL, float thickness = 2); + //----------------------------------------------------------------------------- // Plot and Item Styling //----------------------------------------------------------------------------- diff --git a/implot_demo.cpp b/implot_demo.cpp index cf324e7..7ed9b93 100644 --- a/implot_demo.cpp +++ b/implot_demo.cpp @@ -785,6 +785,23 @@ void ShowDemoWindow(bool* p_open) { } } //------------------------------------------------------------------------- + if (ImGui::CollapsingHeader("Guide Lines")) { + static double v1 = 0.2; + static double v2 = 0.6; + static double h1 = 0.25; + static double h2 = 0.75; + static double h3 = 0.5; + if (ImPlot::BeginPlot("##guides",0,0,ImVec2(-1,0),ImPlotFlags_YAxis2)) { + ImPlot::VerticalGuide("v1",&v1, ImVec4(0,1,0,1)); + ImPlot::VerticalGuide("v2",&v2, ImVec4(0,1,0,1)); + ImPlot::HorizontalGuide("h1",&h1, ImVec4(1,0,0,1)); + ImPlot::HorizontalGuide("h2",&h2, ImVec4(1,0,0,1)); + ImPlot::SetPlotYAxis(1); + ImPlot::HorizontalGuide("h3",&h3, ImVec4(1,1,0,1)); + ImPlot::EndPlot(); + } + } + //------------------------------------------------------------------------- if (ImGui::CollapsingHeader("Drag and Drop")) { const int K_CHANNELS = 9; srand((int)(10000000 * DEMO_TIME)); @@ -1218,38 +1235,6 @@ void ShowDemoWindow(bool* p_open) { } } //------------------------------------------------------------------------- - if (ImGui::CollapsingHeader("Custom Dragable Lines")) { - static float line_value = 0.5f; - const float line_width = 3.0f; - const float grabbable_width = 5.0f; - if (ImPlot::BeginPlot("Dragable Lines")) { - - auto x0 = ImPlot::GetPlotPos().x; - auto x1 = ImPlot::GetPlotPos().x + ImPlot::GetPlotSize().x; - auto y = ImPlot::PlotToPixels(0, line_value).y; - ImPlot::PushPlotClipRect(); - ImPlot::GetPlotDrawList()->AddLine({ x0, y }, { x1, y }, IM_COL32_WHITE, line_width); - ImPlot::PopPlotClipRect(); - - ImVec2 old_cursor_pos = ImGui::GetCursorScreenPos(); - ImVec2 new_cursor_pos = ImVec2(x0, y - grabbable_width / 2.0f); - ImGui::SetItemAllowOverlap(); - ImGui::SetCursorScreenPos(new_cursor_pos); - ImGui::InvisibleButton("horizontal_line", ImVec2(x1 - x0, grabbable_width)); - ImGui::SetCursorScreenPos(old_cursor_pos); - - if (ImGui::IsItemHovered() || ImGui::IsItemActive()) { - ImGui::SetMouseCursor(ImGuiMouseCursor_ResizeNS); - } - - if (ImGui::IsItemActive() && ImGui::IsMouseDragging(0)) { - line_value = ImPlot::GetPlotMousePos().y; - } - - ImPlot::EndPlot(); - } - } - //------------------------------------------------------------------------- ImGui::End(); }