From 109a8632d7617c117d1356265ff31dd658d8f9f1 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 28 May 2024 18:18:35 +0200 Subject: [PATCH] Combo: simplified Combo() API uses a list clipper. Wasn't as trivial before supporting IncludeItemByIndex(). --- docs/CHANGELOG.txt | 2 ++ docs/TODO.txt | 1 - imgui_widgets.cpp | 37 ++++++++++++++++++++----------------- 3 files changed, 22 insertions(+), 18 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index e443b8066..154ae8ff8 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -47,6 +47,8 @@ Other changes: responsible for honoring io.ConfigWindowsMoveFromTitleBarOnly. (#7576, #899) - Scrollbar: made scrolling logic more standard: clicking above or below the grab scrolls by one page, holding mouse button repeats scrolling. (#7328, #150) +- Combo: simplified Combo() API uses a list clipper (due to its api it wasn't + previously trivial before we added clipper.IncludeItemByIndex() function). - Misc: made ImGuiDir and ImGuiSortDirection stronger-typed enums. diff --git a/docs/TODO.txt b/docs/TODO.txt index 734c4d078..eecce6b42 100644 --- a/docs/TODO.txt +++ b/docs/TODO.txt @@ -151,7 +151,6 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - drag float: added leeway on edge (e.g. a few invisible steps past the clamp limits) - combo: a way/helper to customize the combo preview (#1658) -> experimental BeginComboPreview() - - combo: Combo() helper could use clipper. - combo/listbox: keyboard control. need InputText-like non-active focus + key handling. considering keyboard for custom listbox (pr #203) - listbox: multiple selection (WIP range-select branch) - listbox: unselect option (#1208) diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index f09c3c30c..277588e47 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -1952,28 +1952,30 @@ bool ImGui::Combo(const char* label, int* current_item, const char* (*getter)(vo return false; // Display items - // FIXME-OPT: Use clipper (but we need to disable it on the appearing frame to make sure our call to SetItemDefaultFocus() is processed) bool value_changed = false; - for (int i = 0; i < items_count; i++) - { - const char* item_text = getter(user_data, i); - if (item_text == NULL) - item_text = "*Unknown item*"; - - PushID(i); - const bool item_selected = (i == *current_item); - if (Selectable(item_text, item_selected) && *current_item != i) + ImGuiListClipper clipper; + clipper.Begin(items_count); + clipper.IncludeItemByIndex(*current_item); + while (clipper.Step()) + for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) { - value_changed = true; - *current_item = i; + const char* item_text = getter(user_data, i); + if (item_text == NULL) + item_text = "*Unknown item*"; + + PushID(i); + const bool item_selected = (i == *current_item); + if (Selectable(item_text, item_selected) && *current_item != i) + { + value_changed = true; + *current_item = i; + } + if (item_selected) + SetItemDefaultFocus(); + PopID(); } - if (item_selected) - SetItemDefaultFocus(); - PopID(); - } EndCombo(); - if (value_changed) MarkItemEdited(g.LastItemData.ID); @@ -7011,6 +7013,7 @@ bool ImGui::ListBox(const char* label, int* current_item, const char* (*getter)( bool value_changed = false; ImGuiListClipper clipper; clipper.Begin(items_count, GetTextLineHeightWithSpacing()); // We know exactly our line height here so we pass it as a minor optimization, but generally you don't need to. + clipper.IncludeItemByIndex(*current_item); while (clipper.Step()) for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) {