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

[Feature Request] Manually control ScrollArea scroll offset #74

Closed
lucaspoffo opened this issue Dec 21, 2020 · 4 comments · Fixed by #81
Closed

[Feature Request] Manually control ScrollArea scroll offset #74

lucaspoffo opened this issue Dec 21, 2020 · 4 comments · Fixed by #81
Labels
design Some architectual design work needed feature New feature or request

Comments

@lucaspoffo
Copy link
Contributor

lucaspoffo commented Dec 21, 2020

I have the currently scenario:

Peek.2020-12-21.00-46.mp4

that i want to control the scroll when moving the selected line keeping the focus at the active line.

This is what I got trying to achieve this:

Currently the offset state that controls the scroll position is not public. I tried creating an simple public fn to set the offset manually, but since we can't get the Id of the ScrollArea.source_id, we can't change the state. We only have access to the Id of the child_ui (Prepared.content_ui) inside the show() function.

Also since the Prepared state is passed from the begin() to the end(), we can't change it inside the add_contents(). We would need to get the state from the memory again in the end() if we changed it in the add_contents().

Maybe the way out is to pass the Id used to save the state in the return of the show: ScrollArea.show() -> ScrollResponse<R> similar to the CollapsingResponse.

There is probably better solution for this

@lucaspoffo lucaspoffo changed the title [Feature Request] Manually control ScrollArea scroll offset [Feature Request] Manually control ScrollArea scroll offset Dec 21, 2020
@emilk emilk added design Some architectual design work needed feature New feature or request labels Dec 22, 2020
@emilk
Copy link
Owner

emilk commented Dec 22, 2020

There are two scenarios we want to cover:

A) Setting the offset before layout
B) Setting the offset during or after layout

A) Setting the offset before layout

This could be solved with extending the ScrollArea builder like this:

ScrollArea::auto_sized().set_center_offset(500.0).show(...)

where set_center_offset(500) would scroll so that the center of the scroll area focuses 500 points down in the contents.

The downside with this is that one needs to anticipate how many points we want the offset to be ahead of time, which only works for trivial content (e.g. rows of single-line labels).

This should be fairly easy to implement

B) Setting the offset during or after layout

Dear ImGui has a very useful SetScrollHere() function that you can call from within the layout. This will signal the surrounding scroll area to scroll down to that line the next frame.

I think this could be accomplished by something like this:

egui::ScrollArea::auto_sized().show(ui, |ui| {
    for (i, line) in my_text.iter().enumerate() {
        if i == selected_line {
            ui.scroll_to_here();
        }
        ui.label(line);
    }
});

scroll_to_here would set a scroll_offset: Option<f32> in struct FrameState in Context. The scroll area logic would look for that after doing the layout, and store in its own State and use the next frame. The implementation becomes a bit hairy perhaps, but it would be very convenient for the user. In particular, one could call scroll_to_here on any ui deep down far away from any surrounding ScrollArea, and it would still work.

Other considerations

Sometimes one want to center on a particular line, sometimes make it the top of the layout. For centering one also needs to take into account the size of the widget one is centering on, so that we center on the center of the widget. Perhaps:

let response = ui.label(line);
if i == selected_line {        
    response.scroll_to_me(Align::CENTER);
}

Having it part of Response would be neat, as it contains the Rect of the widget we want to center on.

@lucaspoffo
Copy link
Contributor Author

lucaspoffo commented Dec 24, 2020

I'm working on an implementation for this, got the basics from B) done, and works pretty well, this design is pretty good, gets the job done, in my case, with a few lines. Just don't know the best way to achieve:

In particular, one could call scroll_to_here on any ui deep down far away from any surrounding ScrollArea, and it would still work.

Currently you need to call scroll_to_here from the ScrollArea.content_uiin the add_contents callback. What do you think is the ideal way to do that?

@emilk
Copy link
Owner

emilk commented Dec 25, 2020

Currently you need to call scroll_to_here from the ScrollArea.content_uiin the add_contents callback.

Why? Do you have a branch I can look at?

@lucaspoffo
Copy link
Contributor Author

@emilk #81

@emilk emilk closed this as completed in #81 Dec 29, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
design Some architectual design work needed feature New feature or request
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants