Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SetScrollHere and one-frame delays #1526

Closed
franciscod opened this issue Dec 29, 2017 · 15 comments
Closed

SetScrollHere and one-frame delays #1526

franciscod opened this issue Dec 29, 2017 · 15 comments

Comments

@franciscod
Copy link
Contributor

franciscod commented Dec 29, 2017

When using SetScrollHere (example: Demo Window -> Layout -> Scrolling -> drag the "Line = 50") the scrolled content has a ~1frame delay compared with the color highlight. Is there any way to remove this delay?

@franciscod
Copy link
Contributor Author

franciscod commented Mar 17, 2018

I'm really interested in making this delay disappear, even if it's a lot of work. I don't have a clue of where to start, I've been looking at the rendering code but I'm quite lost... any guidance would be much appreciated :)

@franciscod
Copy link
Contributor Author

franciscod commented Mar 17, 2018

49b7a8e

This is the first commit with the scrolling demo in it. Hopefully it will be easier to experiment in a simpler version of imgui :)

For visualization puposes, this reproduces the one-frame delay (replace the for body at line 11479 with this one)

for (int line = 0; line < 100; line++)
                {
                    if (track && line == track_line) {
                        ImGui::Text("Line %d ====", line);
                        ImGui::SetScrollPosHere(i * 0.50f); // 0.0f,0.5f,1.0f
                    } else {
                        ImGui::Text("Line %d", line);
                    }
                }

I tried changing where the Cursor variables are updated (i.e. tried to do it soon as SetScrollPosHere is called) but had no success.

@franciscod
Copy link
Contributor Author

v1.11 repros this if you backport the scrolling demo :)
2402891

paste this around line 6033

    if (ImGui::CollapsingHeader("Scrolling"))
            {

                static bool track = true;
                static int track_line = 50;
                ImGui::Checkbox("Track", &track);
                ImGui::SameLine(); ImGui::SliderInt("##line", &track_line, 0, 99, "Line %.0f");

                    ImGui::BeginChild("asd", ImVec2(ImGui::GetWindowWidth() * 0.25f, 200.0f), true);
                    for (int line = 0; line < 100; line++)
                    {
                        if (track && line == track_line) {
                            ImGui::Text("Line %d ====", line);
                            ImGui::SetScrollPosHere();

                        } else {
                            ImGui::Text("Line %d", line);
                        }
                    }
                    ImGui::EndChild();
            }

@ocornut
Copy link
Owner

ocornut commented Mar 17, 2018

@franciscod SetScrollHere being a function call in the middle of rendering of the window, it's not possible for it to apply the new scrolling immediately. It would require disabling clipping anything ahead of time, or reprocessing from the window another time entirely, etc.

What are you trying to solve exactly? Which problem do you have with that?

It's more likely that the more natural solution would be to adjust the user code. What the demo code does (altering the look of the output based on expected scroll value) is actually quite unusual, in a way the demo is faulty here.

Another possible solution is to have SetNextWindowScroll() function that could be called ahead of Begin. I would like that but right now not sure it is worth exposing more API if you can solve it your problem otherwise.

(I'd like to rework the SetNextWindow/SetWindow entry points to be more flexible. Right now we have too many of them including some using const char* name as input. If I were to redesign the API from stratch today I would maybe consider a more consistent way of identifying windows e.g. SetWindowPos("My Tool", pos); / SetWindowPos(IMGUI_CURRENT_WINDOW, pos); / SetWindowPos(IMGUI_NEXT_WINDOW, pos); .)

@franciscod
Copy link
Contributor Author

Oh, that makes a lot of sense: at the time of SetScrollHere being called, the scroll position for that frame was already decided, so it's natural to have that one frame delay.

I want to have a way to animate a smooth scroll (set the scroll y of THIS frame) a child on a window. I've learned that the only way is setting the scroll before the child's Begin. I'll keep playing, hoping there's a way without exposing more API.

@franciscod
Copy link
Contributor Author

Scrollbars seem to have this 'one-frame scroll' ability, though...

@ocornut
Copy link
Owner

ocornut commented Mar 19, 2018

I want to have a way to animate a smooth scroll (set the scroll y of THIS frame) a child on a window.

You may also be able to reframe the problem or solve it another way but without more information we can't imagine it.

Just create yourself a function for that:

void SetWindowScrollY(const char* name, float scroll_y)
{
    if (ImGuiWindow* window = ImGui::FindWindowByName(name))
    {
        // this is a copy of internal SetWindowScrollY() 
        window->DC.CursorMaxPos.y += window->Scroll.y;
        window->Scroll.y = scroll_y;
        window->DC.CursorMaxPos.y -= window->Scroll.y;
    }
}

Scrollbars seem to have this 'one-frame scroll' ability, though...

Because they are processed in Begin() before the scrolling is locked.

@ocornut
Copy link
Owner

ocornut commented Mar 19, 2018

Variant, this will also work:

void SetWindowScrollY(const char* name, float scroll_y)
{
    if (ImGuiWindow* window = ImGui::FindWindowByName(name))
    {
        ImGuiContext& g = *GImGui;
        ImGuiWindow* backup_window = g.CurrentWindow;
        g.CurrentWindow = window;
        ImGui::SetScrollY(scroll_y);
        g.CurrentWindow = backup_window;
    }
}

The problem from my point of the view (or, the API point of view) is that there are several issues with scrolling and SetXXXWindow functions and I probably need to tackle them together, so I can't just add this entry point in the API. But this function (using imgui_internal.h) will work for your use case.

@franciscod
Copy link
Contributor Author

Awesome! I'll try that as soon as I can and comment on how it worked on my usecase. Thank you Omar, for the in-depth explanations and suggestions :)

@franciscod
Copy link
Contributor Author

franciscod commented Mar 23, 2018

That SetWindowScrollY did wonders! I even got it to snap perfectly by scrolling in increments of (rowHeight + ImGui::GetStyle().ItemSpacing.y) :) Thank you again, Omar!

Not sure if you want to leave this issue open. Maybe open another one for improving the scrolling API? I'm happy to help with that.

@franciscod
Copy link
Contributor Author

FindWindowByName gets tricky on child windows... see #1698

@ocornut
Copy link
Owner

ocornut commented Apr 16, 2020

@franciscod I have added a SetNextWindowScroll() in imgui_internal.h.
It's in internal because I don't have much use cases nor tests for it, but I envision it will probably eventually be moved to imgui.h

@franciscod
Copy link
Contributor Author

franciscod commented Apr 16, 2020

Interesting! I'll check that out. We're already importing imgui_internal.h and using a fair deal of non-exported stuff :) Thanks!

@franciscod
Copy link
Contributor Author

I can confirm SetNextWindowScroll() solves the one-frame delays!

@ocornut
Copy link
Owner

ocornut commented Nov 9, 2022

With commit 7380b98 I have moved SetNextWindowScroll() to imgui.h now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants