epezent / implot

Immediate Mode Plotting
MIT License
4.78k stars 531 forks source link

DragLineX/Y cannot be accessed when are dragged out of plot area with ImPlotCond_Always #302

Open MichaelKv opened 2 years ago

MichaelKv commented 2 years ago

Hello, From implot.h // ImPlot version string.

define IMPLOT_VERSION "0.13 WIP"

I need fixed axes so I have changed ImPlot::SetupAxesLimits(0,1,0,1); to ImPlot::SetupAxesLimits(0, 1, 0, 1, ImPlotCond_Always); in void ShowDemo_DragLines(). I can drag lines out of axes region pretty well indeed so I cannot get them back. Is there a way to make draglines to stop at the edges of the plot area the way your online demo does?

P.S. I cannot reproduce it in your demo but in my application I have the additional problem: while dragging the DragLineX out of the plot to the left the Y axis highlights and at this very moment all visible graphics (I have plenty of them and they do not fit to the screen so there is a scroller if it is important) change their color like here https://github.com/epezent/implot/issues/301 . But if I scroll (ImGUI scrolling, I do nothing to scroll) down to the next graphics they have normal color. In your demo the Y axis does not highlight and there are no additional problems except your DragLineXs cannot be accessed anymore too.

epezent commented 2 years ago

You can just add a constaint on the variable passed to DragLineX immediately after you call the function (e.g. std::clamp(x,0,1)). Note you may need to pass the following flag to get the behavior you want:

ImPlotDragToolFlags_Delayed   = 1 << 3, // tool rendering will be delayed one frame; useful when applying position-constraints

Regarding your other issue, I'm struggling to imagine what you are describing. A GIF or video would be helpful. In the context of #301, I suspect you are misusing ImGui/ImPlot IDs (e.g. reusing ID strings for multiple plots). Again, I can't offer much help until you can provide reproducable code or address the points I raised before.

epezent commented 2 years ago

We could also add a flag, e.g. ImPlotDragToolFlags_Clamp, to clamp the tool position to the plot boundary.

MichaelKv commented 2 years ago

I have not checked the flags yet – I have been spending the night figuring out what was happening to the color change because it looked like a memory corruption. My application stops providing the storage for x for IMPLOT_API bool DragLineX(int id, double* x, const ImVec4& col, float thickness = 1, ImPlotDragToolFlags flags = ImPlotDragToolFlags_None); call when x goes out of plot so it stops calling DragLineX abruptly. If I provide a fake storage for x (a static variable as in your demo) and continue to call DragLineX with this dummy storage when x is out of scope than everything works as in your demo. Please, see the complete ShowDemo_DragLines modified code below. It shall illustrate my case. The color of the "Interactive Data" changes when x goes out of scope. If you uncomment AAAA (the second vert. line) than it will begin to glitch a little bit differently. Even if I somehow misuse ImPlot the situation is very tricky. At least for me. P.S. the code:

` void ShowDemo_DragLines() { ImGui::BulletText("Click and drag the horizontal and vertical lines."); static double x1 = 0.2; static double x2 = 0.8; static double y1 = 0.25; static double y2 = 0.75; static double f = 0.1; ImGui::SetNextWindowSize(ImGui::GetIO().DisplaySize); ImGui::SetNextWindowPos(ImVec2()); ImGui::Begin("AAA", nullptr, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize); ImVec2 graphWindowSize = ImGui::GetContentRegionAvail();// ImGui::GetWindowSize(); constexpr size_t GraphAmount = 15; ImVec2 oneGraphSize = ImVec2(-1, graphWindowSize.y / GraphAmount); if (oneGraphSize.y < 150.f) { oneGraphSize.y = 150.f; }

static ImPlotDragToolFlags flags = ImPlotDragToolFlags_None;
ImGui::CheckboxFlags("NoCursors", (unsigned int*)&flags, ImPlotDragToolFlags_NoCursors); ImGui::SameLine();
ImGui::CheckboxFlags("NoFit", (unsigned int*)&flags, ImPlotDragToolFlags_NoFit); ImGui::SameLine();
ImGui::CheckboxFlags("NoInput", (unsigned int*)&flags, ImPlotDragToolFlags_NoInputs);
ImGui::BeginChild("GraphWindow", graphWindowSize, false);
for (size_t i = 0; i < GraphAmount; ++i) {
    std::string s = "##lines" + std::to_string(i);
    if (ImPlot::BeginPlot(s.c_str(), oneGraphSize)) {
        ImPlot::SetupAxesLimits(0, 1, 0, 1, ImPlotCond_Always);
        if (x1 >= 0. && x1 <= 1.) {
            ImPlot::DragLineX(0, &x1, ImVec4(1, 1, 1, 1), 1, flags);
        }
        if (x2 >= 0. && x2 <= 1.) {
            //ImPlot::DragLineX(1, &x2, ImVec4(1, 1, 1, 1), 1, flags); // AAAA
        }
        ImPlot::DragLineY(2, &y1, ImVec4(1, 1, 1, 1), 1, flags);
        ImPlot::DragLineY(3, &y2, ImVec4(1, 1, 1, 1), 1, flags);
        double xs[1000], ys[1000];
        for (int i = 0; i < 1000; ++i) {
            xs[i] = (x2 + x1) / 2 + fabs(x2 - x1) * (i / 1000.0f - 0.5f);
            ys[i] = (y1 + y2) / 2 + fabs(y2 - y1) / 2 * sin(f * i / 10);
        }
        ImPlot::PlotLine("Interactive Data", xs, ys, 1000);
        ImPlot::DragLineY(120482, &f, ImVec4(1, 0.5f, 1, 1), 1, flags);
        ImPlot::EndPlot();
    }
}
ImGui::EndChild();
ImGui::End();

} `

epezent commented 2 years ago

Thanks for sharing the code. I tested your example and was able to reproduce the"color" issue iwhen the DragLine is moved off plot. I am not sure what the problem is yet, but I will work on it. Will report back later.

PS -- you are using twice defining the variable i in your outer loop and inner loop

MichaelKv commented 2 years ago

While considering a solution, please, note that an abruption may occur due to an asynchronous interrupt (from a hardware, for example). So far the ImGui/ImPlot usage is extremely hard in such environments. Moreover, the big problem is that C++ language helpers does not always help and one needs a methodological guidance that lacks. Thanks for your notice about the variable.