MultiSelect: Demo: added simpler demo using Clipper. Clarify RangeSrcPassedBy doc.

This commit is contained in:
ocornut 2023-08-23 19:47:24 +02:00
parent c3753809b1
commit 6ddc5f38af
2 changed files with 52 additions and 8 deletions

12
imgui.h
View File

@ -2774,11 +2774,13 @@ enum ImGuiMultiSelectFlags_
// Usage flow:
// BEGIN - (1) Call BeginMultiSelect() and retrieve the ImGuiMultiSelectIO* result.
// - (2) [If using clipper] Honor Clear/SelectAll/SetRange requests by updating your selection data. Same code as Step 6.
// LOOP - (3) [If using clipper] Set RangeSrcPassedBy=true if the RangeSrcItem item is part of the items clipped before the first submitted/visible item.
// LOOP - (3) [If using clipper] Set RangeSrcPassedBy=true if the RangeSrcItem item was already passed by.
// This is because for range-selection we need to know if we are currently "inside" or "outside" the range.
// - If you are using integer indices in ImGuiSelectionUserData, this is easy to compute: if (clipper.DisplayStart > data->RangeSrcItem) { data->RangeSrcPassedBy = true; }
// - If you are using pointers in ImGuiSelectionUserData, you may need additional processing in each clipper step to tell if current DisplayStart comes after RangeSrcItem..
// - (4) Submit your items with SetNextItemSelectionUserData() + Selectable()/TreeNode() calls. (optionally call IsItemToggledSelection() if you need that info immediately for displaying your item, before EndMultiSelect())
// - If you are using integer indices in ImGuiSelectionUserData, this is easy to compute:
// if (clipper.DisplayStart > data->RangeSrcItem) { data->RangeSrcPassedBy = true; }
// - If you are using pointers in ImGuiSelectionUserData, you may need additional processing, e.g. find the index of RangeSrcItem before applying the above operation.
// - This also needs to be done at the end of the clipper loop, otherwise we can't tell if the item still exist.
// - (4) Submit your items with SetNextItemSelectionUserData() + Selectable()/TreeNode() calls.
// END - (5) Call EndMultiSelect() and retrieve the ImGuiMultiSelectIO* result.
// - (6) Honor Clear/SelectAll/SetRange requests by updating your selection data. Same code as Step 2.
// If you submit all items (no clipper), Step 2 and 3 and will be handled by Selectable()/TreeNode on a per-item basis.
@ -2801,7 +2803,7 @@ struct ImGuiMultiSelectIO
ImGuiSelectionUserData RangeFirstItem; // / / ms:w, app:r // End: parameter for RequestSetRange request (this is generally == RangeSrcItem when shift selecting from top to bottom)
ImGuiSelectionUserData RangeLastItem; // / / ms:w, app:r // End: parameter for RequestSetRange request (this is generally == RangeSrcItem when shift selecting from bottom to top)
bool RangeSelected; // / / ms:w, app:r // End: parameter for RequestSetRange request. true = Select Range, false = Unselect Range.
bool RangeSrcPassedBy; // / ms:rw app:w / ms:r // (If using clipper) Need to be set by app/user if RangeSrcItem was part of the clipped set before submitting the visible items. Ignore if not clipping.
bool RangeSrcPassedBy; // / ms:rw app:w / ms:r // (If using clipper) Need to be set by app/user if RangeSrcItem was passed by. Ignore if not clipping.
bool RangeSrcReset; // app:w / app:w / ms:r // (If using deletion) Set before EndMultiSelect() to reset ResetSrcItem (e.g. if deleted selection).
bool NavIdSelected; // ms:w, app:r / / // (If using deletion) Last known selection state for NavId (if part of submitted items).
ImGuiSelectionUserData NavIdItem; // ms:w, app:r / / // (If using deletion) Last known SetNextItemSelectionUserData() value for NavId (if part of submitted items).

View File

@ -2911,7 +2911,7 @@ static void ShowDemoWindowMultiSelect()
ImGui::TreePop();
}
const char* random_names[] =
static const char* random_names[] =
{
"Artichoke", "Arugula", "Asparagus", "Avocado", "Bamboo Shoots", "Bean Sprouts", "Beans", "Beet", "Belgian Endive", "Bell Pepper",
"Bitter Gourd", "Bok Choy", "Broccoli", "Brussels Sprouts", "Burdock Root", "Cabbage", "Calabash", "Capers", "Carrot", "Cassava",
@ -2935,7 +2935,7 @@ static void ShowDemoWindowMultiSelect()
// The BeginListBox() has no actual purpose for selection logic (other that offering a scrolling region).
const int ITEMS_COUNT = 50;
ImGui::Text("Selection size: %d", selection.GetSize());
ImGui::Text("Selection: %d/%d", selection.GetSize(), ITEMS_COUNT);
if (ImGui::BeginListBox("##Basket", ImVec2(-FLT_MIN, ImGui::GetFontSize() * 20)))
{
ImGuiMultiSelectFlags flags = ImGuiMultiSelectFlags_ClearOnEscape;
@ -2951,7 +2951,49 @@ static void ShowDemoWindowMultiSelect()
ImGui::Selectable(label, item_is_selected);
}
// Apply multi-select requests
ms_io = ImGui::EndMultiSelect();
selection.ApplyRequests(ms_io, ITEMS_COUNT);
ImGui::EndListBox();
}
ImGui::TreePop();
}
// Demonstrate using the clipper with BeginMultiSelect()/EndMultiSelect()
IMGUI_DEMO_MARKER("Widgets/Selection State/Multi-Select (with clipper)");
if (ImGui::TreeNode("Multi-Select (with clipper)"))
{
static ExampleSelection selection;
ImGui::Text("Added features:");
ImGui::BulletText("Using ImGuiListClipper.");
const int ITEMS_COUNT = 10000;
ImGui::Text("Selection: %d/%d", selection.GetSize(), ITEMS_COUNT);
if (ImGui::BeginListBox("##Basket", ImVec2(-FLT_MIN, ImGui::GetFontSize() * 20)))
{
ImGuiMultiSelectFlags flags = ImGuiMultiSelectFlags_ClearOnEscape;
ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(flags);
selection.ApplyRequests(ms_io, ITEMS_COUNT);
ImGuiListClipper clipper;
clipper.Begin(ITEMS_COUNT);
while (clipper.Step())
{
if (!ms_io->RangeSrcPassedBy && clipper.DisplayStart > ms_io->RangeSrcItem)
ms_io->RangeSrcPassedBy = true;
for (int n = clipper.DisplayStart; n < clipper.DisplayEnd; n++)
{
char label[64];
sprintf(label, "Object %05d: %s", n, random_names[n % IM_ARRAYSIZE(random_names)]);
bool item_is_selected = selection.Contains(n);
ImGui::SetNextItemSelectionUserData(n);
ImGui::Selectable(label, item_is_selected);
}
}
if (!ms_io->RangeSrcPassedBy && ITEMS_COUNT > ms_io->RangeSrcItem)
ms_io->RangeSrcPassedBy = true;
ms_io = ImGui::EndMultiSelect();
selection.ApplyRequests(ms_io, ITEMS_COUNT);