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

How to have scrolling working with selected items in a listbox ? #4242

Closed
rtoumazet opened this issue Jun 19, 2021 · 9 comments
Closed

How to have scrolling working with selected items in a listbox ? #4242

rtoumazet opened this issue Jun 19, 2021 · 9 comments
Labels
focus nav keyboard/gamepad navigation scrolling selection

Comments

@rtoumazet
Copy link

Version/Branch of Dear ImGui:

Version: 1.83
Branch: master

Back-end/Renderer/Compiler/OS

Back-ends: imgui_impl_opengl3.cpp
Operating System: Windows

Hi.

I'm trying to have scrolling working with selected items in a listbox, using the keyboard.
If no element is highlighted in the listbox, moving from element to element using up and down arrow of the keyboard works fine, but as you can see in the video scrolling doesn't follow the selection :

imgui_listbox_no_scroll

When one element is highlighted, the scrolling works following the current highlighted element. Unfortunately, when the up or down key is kept down, the selected and highlighted element are getting desynchronized :

imgui_listbox_scroll_desynchro

What is the best way to have the scrolling in phase with the selected element, instead of the highlighted one ?

Thank you !

Standalone, minimal, complete and verifiable example: (see #2261)

// Here's the code used for both captures, 
        {
            // Draw list
            ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2());
            const auto child_size = ImVec2(310, 280);
            ImGui::BeginChild("ChildDrawList", child_size, true, window_flags | ImGuiWindowFlags_MenuBar);

            // ImGui::ChildWindowHeader(tr("Draw list"));
            if (ImGui::BeginMenuBar()) {
                ImGui::TextUnformatted(tr("Draw list").c_str());
                ImGui::EndMenuBar();
            }
            const auto  draw_list_size = ImVec2(310, 260);
            const char* items[] = {"AAAA",    "BBBB", "CCCC", "DDDD",  "EEEE", "FFFF",  "GGGG",  "HHHH", "IIII",   "JJJJ", "KKKK",
                                   "LLLLLLL", "MMMM", "NNNN", "OOOOO", "PPP",  "QQQQQ", "RRRRR", "SSSS", "TTTTTT", "UUU"};
            if (ImGui::BeginListBox("##draw_list", draw_list_size)) {
                if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_DownArrow))) {
                    if (current_part_idx < draw_list.size() - 1) { ++current_part_idx; }
                }
                if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_UpArrow))) {
                    if (current_part_idx > 0) { --current_part_idx; }
                }

                for (int n = 0; n < IM_ARRAYSIZE(items); ++n) {
                    const bool is_selected = (current_part_idx == n);
                    if (ImGui::Selectable(items[n], is_selected)) { current_part_idx = n; }

                    // Set the initial focus when opening the combo (scrolling + keyboard navigation focus)
                    if (is_selected) { ImGui::SetItemDefaultFocus(); }
                }
                ImGui::EndListBox();
            }

            ImGui::EndChild();
            ImGui::PopStyleVar();
        }
@ocornut ocornut added focus nav keyboard/gamepad navigation scrolling labels Jun 21, 2021
@ocornut
Copy link
Owner

ocornut commented Jun 21, 2021

Have you tried enabling keyboard navigation?
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
You can move and select items with keyboard, and the movement already handle scroll tracking, so your key handling code could be removed and scrolling would work properly

There's currently no standalone function to force that scroll in the desirable way other than ScrollToBringRectIntoView() in imgui_internal.h. We have yet to design a public facing wrapper which would handle the fact that depending on context we want items to appear at the center or at the edge (in most situations we want items at the center when window appears, and follow the edge when manually altered afterwards).
More ref #3692 #3578 #3208

@rtoumazet
Copy link
Author

Actually io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard is enabled in my app, but its default behaviour isn't working the way I want.
Using it, you can move the highlighted element up and down, with the scrolling following its position, but you still need to press the spacebar in order to select the highlighted element.
What I want to achieve is to have the keyboard navigation automatically select the highlighted element, without the need to press the spacebar ... ie you are on the first element of the listbox, you press the down arrow -> the second element is highlighted and selected directly.

@ocornut
Copy link
Owner

ocornut commented Jun 21, 2021

Actually io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard is enabled in my app,

Apologies: I had indeed skimmed through the first part of your initial message :(

What I want to achieve is to have the keyboard navigation automatically select the highlighted element, without the need to press the spacebar

I see. We have this feature in the range-select branch. I would like to investigate back-porting it to master.

However it's important to understand it only makes sense when the scopes are explicitly marked (otherwise there's no way to distinguish multiple selectable sets) + it needs a concept of restoring navigation id when reentering the scope. Let me investigate this.

ocornut added a commit that referenced this issue Jun 21, 2021
…of if (hovered || selected) tests. Should make no difference as NavId currently returns hovered. (#1861, #4242)
ocornut added a commit that referenced this issue Jun 21, 2021
…Nav with comments and caveats. (#1861, #4242,)

Focus scope default value: amend 7ee623d a5041c8 2ebe08b
@ocornut
Copy link
Owner

ocornut commented Jun 21, 2021

I have a pushed a few changes in the form of a ImGuiSelectableFlags_SelectOnNav flag (declared to imgui_internal.h) to auto-select when moved into.

It's a relatively simple change and can be used for single-selection.
It makes the moved-on Selectable() returns true and will ensure it is not clipped.

For multi-selection it's not usable as easily.

// Auto-select when moved into
// - This will be more fully fleshed in the range-select branch
// - This is not exposed as it won't nicely work with some user side handling of shift/control
// - We cannot "unselect other selectables" with e.g. 'if (g.NavJustMovedToId != id) { selected = false; pressed = was_selected; }' for two reasons
//   - (1) it would require focus scope to be set, need exposing PushFocusScope() or equivalent (e.g. BeginSelection() calling PushFocusScope())
//   - (2) usage will fail with clipped items
//   The multi-select API aim to fix those issues, e.g. may be replaced with a BeginSelection() API.

@rtoumazet
Copy link
Author

Looks good to me 👍

@rtoumazet
Copy link
Author

Just tested it in my app ... works like a charm !
Thanks again Omar ;)

rtoumazet added a commit to rtoumazet/saturnin that referenced this issue Aug 25, 2021
ocornut added a commit that referenced this issue Sep 29, 2021
ocornut added a commit that referenced this issue Sep 29, 2021
ocornut added a commit that referenced this issue Nov 2, 2021
…ed (fix nav in one axis scrolling back and forth between axises when space is tight by just < ItemSpacing*2) (#3692, #2812, #4242, #2900)

Amend 8f495e5
actondev pushed a commit to actondev/imgui that referenced this issue Nov 26, 2021
…ed (fix nav in one axis scrolling back and forth between axises when space is tight by just < ItemSpacing*2) (ocornut#3692, ocornut#2812, ocornut#4242, ocornut#2900)

Amend 8f495e5
ocornut added a commit that referenced this issue Nov 24, 2022
…ocus()/ScrollToRectEx() during an appearing form not centering item. (#5902, #2812, #4242, #2900)

Amend 44f8011 and 8f495e5
ocornut pushed a commit that referenced this issue Dec 20, 2022
…tered element that is not visible but could be would take the item's Y coordinate into account.

Neither behavior were used in the codebase for this axis.
Amend 27c58c3 (#5902, #2812, #4242, #2900)
Signed-off-by: Neil Bickford <[email protected]>
@MacQuant
Copy link

MacQuant commented Apr 3, 2023

Could you please provide an example that works for this please? I have tried but no luck. If you could past a simple example that would be great please

@rtoumazet
Copy link
Author

Hi @MacQuant ,
Here's the relevant part of my code :

ImGuiIO&  io = ImGui::GetIO();
io.WantCaptureKeyboard = true;

...
      
const auto draw_list_size = ImVec2(310, 260);
if (ImGui::BeginListBox("##draw_list", draw_list_size)) {
    for (u32 n = 0; n < draw_list.size(); ++n) {
        const bool is_selected = (current_part_idx == n);
        if (ImGui::Selectable(format("{}##{}", draw_list[n].debugHeader(), n).c_str(), is_selected, ImGuiSelectableFlags_SelectOnNav)) {
                        current_part_idx = n;
        }

       // Set the initial focus when opening the combo (scrolling + keyboard navigation focus)
       if (is_selected) { ImGui::SetItemDefaultFocus(); }
     }
    ImGui::EndListBox();
}

Hope it helps :)

@MacQuant
Copy link

MacQuant commented Apr 4, 2023

@rtoumazet
Works perfect, thanks so much!!

maztheman pushed a commit to maztheman/imgui that referenced this issue Mar 10, 2025
…tered element that is not visible but could be would take the item's Y coordinate into account.

Neither behavior were used in the codebase for this axis.
Amend 27c58c3 (ocornut#5902, ocornut#2812, ocornut#4242, ocornut#2900)
Signed-off-by: Neil Bickford <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
focus nav keyboard/gamepad navigation scrolling selection
Projects
None yet
Development

No branches or pull requests

3 participants