mirror of https://github.com/ocornut/imgui
MultiSelect: (breaking) Added 'items_count' parameter to BeginMultiSelect(). Will enable extra features, and remove equivalent param from ImGuiSelectionBasicStorage::ApplyRequests(.
This commit is contained in:
parent
443b034895
commit
ab995d3d4f
12
imgui.h
12
imgui.h
|
@ -179,7 +179,7 @@ struct ImGuiMultiSelectIO; // Structure to interact with a BeginMultiSe
|
|||
struct ImGuiOnceUponAFrame; // Helper for running a block of code not more than once a frame
|
||||
struct ImGuiPayload; // User data payload for drag and drop operations
|
||||
struct ImGuiPlatformImeData; // Platform IME data for io.PlatformSetImeDataFn() function.
|
||||
struct ImGuiSelectionBasicStorage; // Helper struct to store multi-selection state + apply multi-selection requests.
|
||||
struct ImGuiSelectionBasicStorage; // Optional helper to store multi-selection state + apply multi-selection requests.
|
||||
struct ImGuiSelectionRequest; // A selection request (stored in ImGuiMultiSelectIO)
|
||||
struct ImGuiSizeCallbackData; // Callback data when using SetNextWindowSizeConstraints() (rare/advanced use)
|
||||
struct ImGuiStorage; // Helper for key->value storage (container sorted by key)
|
||||
|
@ -673,9 +673,10 @@ namespace ImGui
|
|||
|
||||
// Multi-selection system for Selectable() and TreeNode() functions.
|
||||
// - This enables standard multi-selection/range-selection idioms (CTRL+Mouse/Keyboard, SHIFT+Mouse/Keyboard, etc.) in a way that also allow a clipper to be used.
|
||||
// - ImGuiSelectionUserData is often used to store your item index.
|
||||
// - ImGuiSelectionUserData is often used to store your item index within the current view (but may store something else).
|
||||
// - Read comments near ImGuiMultiSelectIO for instructions/details and see 'Demo->Widgets->Selection State & Multi-Select' for demo.
|
||||
IMGUI_API ImGuiMultiSelectIO* BeginMultiSelect(ImGuiMultiSelectFlags flags, int current_selection_size = -1);
|
||||
// - 'selection_size' and 'items_count' parameters are optional and used by a few features. If they are costly for you to compute, you may avoid them.
|
||||
IMGUI_API ImGuiMultiSelectIO* BeginMultiSelect(ImGuiMultiSelectFlags flags, int selection_size = -1, int items_count = -1);
|
||||
IMGUI_API ImGuiMultiSelectIO* EndMultiSelect();
|
||||
IMGUI_API void SetNextItemSelectionUserData(ImGuiSelectionUserData selection_user_data);
|
||||
IMGUI_API bool IsItemToggledSelection(); // Was the last item selection state toggled? Useful if you need the per-item information _before_ reaching EndMultiSelect(). We only returns toggle _event_ in order to handle clipping correctly.
|
||||
|
@ -2799,6 +2800,7 @@ struct ImGuiMultiSelectIO
|
|||
ImGuiSelectionUserData NavIdItem; // ms:w, app:r / // (If using deletion) Last known SetNextItemSelectionUserData() value for NavId (if part of submitted items).
|
||||
bool NavIdSelected; // ms:w, app:r / app:r // (If using deletion) Last known selection state for NavId (if part of submitted items).
|
||||
bool RangeSrcReset; // app:w / ms:r // (If using deletion) Set before EndMultiSelect() to reset ResetSrcItem (e.g. if deleted selection).
|
||||
int ItemsCount; // ms:w, app:r / app:r // 'int items_count' parameter to BeginMultiSelect() is copied here for convenience, allowing simpler calls to your ApplyRequests handler. Not used internally.
|
||||
};
|
||||
|
||||
// Selection request type
|
||||
|
@ -2846,8 +2848,8 @@ struct ImGuiSelectionBasicStorage
|
|||
ImGuiID (*AdapterIndexToStorageId)(ImGuiSelectionBasicStorage* self, int idx); // e.g. selection.AdapterIndexToStorageId = [](ImGuiSelectionBasicStorage* self, int idx) { return ((MyItems**)self->AdapterData)[idx]->ID; };
|
||||
void* UserData; // User data for use by adapter function // e.g. selection.UserData = (void*)my_items;
|
||||
|
||||
// Methods: apply selection requests coming from BeginMultiSelect() and EndMultiSelect() functions
|
||||
IMGUI_API void ApplyRequests(ImGuiMultiSelectIO* ms_io, int items_count);
|
||||
// Methods: apply selection requests coming from BeginMultiSelect() and EndMultiSelect() functions. Uses 'items_count' based to BeginMultiSelect()
|
||||
IMGUI_API void ApplyRequests(ImGuiMultiSelectIO* ms_io);
|
||||
|
||||
// Methods: selection storage
|
||||
ImGuiSelectionBasicStorage() { Clear(); UserData = NULL; AdapterIndexToStorageId = [](ImGuiSelectionBasicStorage*, int idx) { return (ImGuiID)idx; }; }
|
||||
|
|
|
@ -2874,7 +2874,7 @@ struct ExampleDualListBox
|
|||
// In this example we store item id in selection (instead of item index)
|
||||
Selections[side].UserData = Items[side].Data;
|
||||
Selections[side].AdapterIndexToStorageId = [](ImGuiSelectionBasicStorage* self, int idx) { ImGuiID* items = (ImGuiID*)self->UserData; return items[idx]; };
|
||||
Selections[side].ApplyRequests(ms_io, Items[side].Size);
|
||||
Selections[side].ApplyRequests(ms_io);
|
||||
}
|
||||
static int IMGUI_CDECL CompareItemsByValue(const void* lhs, const void* rhs)
|
||||
{
|
||||
|
@ -2929,7 +2929,7 @@ struct ExampleDualListBox
|
|||
if (child_visible)
|
||||
{
|
||||
ImGuiMultiSelectFlags flags = ImGuiMultiSelectFlags_None;
|
||||
ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(flags, selection.Size);
|
||||
ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(flags, selection.Size, items.Size);
|
||||
ApplySelectionRequests(ms_io, side);
|
||||
|
||||
for (int item_n = 0; item_n < items.Size; item_n++)
|
||||
|
@ -3060,8 +3060,8 @@ static void ShowDemoWindowMultiSelect()
|
|||
if (ImGui::BeginChild("##Basket", ImVec2(-FLT_MIN, ImGui::GetFontSize() * 20), ImGuiChildFlags_FrameStyle | ImGuiChildFlags_ResizeY))
|
||||
{
|
||||
ImGuiMultiSelectFlags flags = ImGuiMultiSelectFlags_ClearOnEscape | ImGuiMultiSelectFlags_BoxSelect1d;
|
||||
ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(flags, selection.Size);
|
||||
selection.ApplyRequests(ms_io, ITEMS_COUNT);
|
||||
ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(flags, selection.Size, ITEMS_COUNT);
|
||||
selection.ApplyRequests(ms_io);
|
||||
|
||||
for (int n = 0; n < ITEMS_COUNT; n++)
|
||||
{
|
||||
|
@ -3073,7 +3073,7 @@ static void ShowDemoWindowMultiSelect()
|
|||
}
|
||||
|
||||
ms_io = ImGui::EndMultiSelect();
|
||||
selection.ApplyRequests(ms_io, ITEMS_COUNT);
|
||||
selection.ApplyRequests(ms_io);
|
||||
}
|
||||
ImGui::EndChild();
|
||||
ImGui::TreePop();
|
||||
|
@ -3094,8 +3094,8 @@ static void ShowDemoWindowMultiSelect()
|
|||
if (ImGui::BeginChild("##Basket", ImVec2(-FLT_MIN, ImGui::GetFontSize() * 20), ImGuiChildFlags_FrameStyle | ImGuiChildFlags_ResizeY))
|
||||
{
|
||||
ImGuiMultiSelectFlags flags = ImGuiMultiSelectFlags_ClearOnEscape | ImGuiMultiSelectFlags_BoxSelect1d;
|
||||
ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(flags, selection.Size);
|
||||
selection.ApplyRequests(ms_io, ITEMS_COUNT);
|
||||
ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(flags, selection.Size, ITEMS_COUNT);
|
||||
selection.ApplyRequests(ms_io);
|
||||
|
||||
ImGuiListClipper clipper;
|
||||
clipper.Begin(ITEMS_COUNT);
|
||||
|
@ -3114,7 +3114,7 @@ static void ShowDemoWindowMultiSelect()
|
|||
}
|
||||
|
||||
ms_io = ImGui::EndMultiSelect();
|
||||
selection.ApplyRequests(ms_io, ITEMS_COUNT);
|
||||
selection.ApplyRequests(ms_io);
|
||||
}
|
||||
ImGui::EndChild();
|
||||
ImGui::TreePop();
|
||||
|
@ -3158,8 +3158,8 @@ static void ShowDemoWindowMultiSelect()
|
|||
if (ImGui::BeginChild("##Basket", ImVec2(-FLT_MIN, ImGui::GetFontSize() * 20), ImGuiChildFlags_FrameStyle | ImGuiChildFlags_ResizeY))
|
||||
{
|
||||
ImGuiMultiSelectFlags flags = ImGuiMultiSelectFlags_ClearOnEscape | ImGuiMultiSelectFlags_BoxSelect1d;
|
||||
ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(flags, selection.Size);
|
||||
selection.ApplyRequests(ms_io, items.Size);
|
||||
ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(flags, selection.Size, items.Size);
|
||||
selection.ApplyRequests(ms_io);
|
||||
|
||||
const bool want_delete = ImGui::Shortcut(ImGuiKey_Delete, ImGuiInputFlags_Repeat) && (selection.Size > 0);
|
||||
const int item_curr_idx_to_focus = want_delete ? selection.ApplyDeletionPreLoop(ms_io, items.Size) : -1;
|
||||
|
@ -3179,7 +3179,7 @@ static void ShowDemoWindowMultiSelect()
|
|||
|
||||
// Apply multi-select requests
|
||||
ms_io = ImGui::EndMultiSelect();
|
||||
selection.ApplyRequests(ms_io, items.Size);
|
||||
selection.ApplyRequests(ms_io);
|
||||
if (want_delete)
|
||||
selection.ApplyDeletionPostLoop(ms_io, items, item_curr_idx_to_focus);
|
||||
}
|
||||
|
@ -3275,8 +3275,8 @@ static void ShowDemoWindowMultiSelect()
|
|||
{
|
||||
ImGui::PushID(selection_scope_n);
|
||||
ImGuiSelectionBasicStorage* selection = &selections_data[selection_scope_n];
|
||||
ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(flags, selection->Size);
|
||||
selection->ApplyRequests(ms_io, ITEMS_COUNT);
|
||||
ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(flags, selection->Size, ITEMS_COUNT);
|
||||
selection->ApplyRequests(ms_io);
|
||||
|
||||
ImGui::SeparatorText("Selection scope");
|
||||
ImGui::Text("Selection size: %d/%d", selection->Size, ITEMS_COUNT);
|
||||
|
@ -3292,7 +3292,7 @@ static void ShowDemoWindowMultiSelect()
|
|||
|
||||
// Apply multi-select requests
|
||||
ms_io = ImGui::EndMultiSelect();
|
||||
selection->ApplyRequests(ms_io, ITEMS_COUNT);
|
||||
selection->ApplyRequests(ms_io);
|
||||
ImGui::PopID();
|
||||
}
|
||||
ImGui::TreePop();
|
||||
|
@ -3375,8 +3375,8 @@ static void ShowDemoWindowMultiSelect()
|
|||
if (widget_type == WidgetType_TreeNode)
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(ImGui::GetStyle().ItemSpacing.x, 0.0f));
|
||||
|
||||
ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(flags, selection.Size);
|
||||
selection.ApplyRequests(ms_io, items.Size);
|
||||
ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(flags, selection.Size, items.Size);
|
||||
selection.ApplyRequests(ms_io);
|
||||
|
||||
const bool want_delete = (ImGui::Shortcut(ImGuiKey_Delete, ImGuiInputFlags_Repeat) && (selection.Size > 0)) || request_deletion_from_menu;
|
||||
const int item_curr_idx_to_focus = want_delete ? selection.ApplyDeletionPreLoop(ms_io, items.Size) : -1;
|
||||
|
@ -3520,7 +3520,7 @@ static void ShowDemoWindowMultiSelect()
|
|||
|
||||
// Apply multi-select requests
|
||||
ms_io = ImGui::EndMultiSelect();
|
||||
selection.ApplyRequests(ms_io, items.Size);
|
||||
selection.ApplyRequests(ms_io);
|
||||
if (want_delete)
|
||||
selection.ApplyDeletionPostLoop(ms_io, items, item_curr_idx_to_focus);
|
||||
|
||||
|
@ -9846,12 +9846,12 @@ struct ExampleAssetsBrowser
|
|||
ms_flags |= ImGuiMultiSelectFlags_SelectOnClickRelease; // To allow dragging an unselected item without altering selection.
|
||||
if (AllowBoxSelect)
|
||||
ms_flags |= ImGuiMultiSelectFlags_BoxSelect; // Enable box-select in 2D mode.
|
||||
ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(ms_flags, Selection.Size);
|
||||
ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(ms_flags, Selection.Size, Items.Size);
|
||||
|
||||
// Use custom selection adapter: store ID in selection (recommended)
|
||||
Selection.UserData = this;
|
||||
Selection.AdapterIndexToStorageId = [](ImGuiSelectionBasicStorage* self_, int idx) { ExampleAssetsBrowser* self = (ExampleAssetsBrowser*)self_->UserData; return self->Items[idx].ID; };
|
||||
Selection.ApplyRequests(ms_io, Items.Size);
|
||||
Selection.ApplyRequests(ms_io);
|
||||
|
||||
const bool want_delete = (ImGui::Shortcut(ImGuiKey_Delete, ImGuiInputFlags_Repeat) && (Selection.Size > 0)) || RequestDelete;
|
||||
const int item_curr_idx_to_focus = want_delete ? Selection.ApplyDeletionPreLoop(ms_io, Items.Size) : -1;
|
||||
|
@ -9959,7 +9959,7 @@ struct ExampleAssetsBrowser
|
|||
}
|
||||
|
||||
ms_io = ImGui::EndMultiSelect();
|
||||
Selection.ApplyRequests(ms_io, Items.Size);
|
||||
Selection.ApplyRequests(ms_io);
|
||||
if (want_delete)
|
||||
Selection.ApplyDeletionPostLoop(ms_io, Items, item_curr_idx_to_focus);
|
||||
|
||||
|
|
|
@ -7300,10 +7300,13 @@ static void DebugLogMultiSelectRequests(const char* function, const ImGuiMultiSe
|
|||
|
||||
// Return ImGuiMultiSelectIO structure.
|
||||
// Lifetime: don't hold on ImGuiMultiSelectIO* pointers over multiple frames or past any subsequent call to BeginMultiSelect() or EndMultiSelect().
|
||||
// Passing 'current_selection_size' is currently optional:
|
||||
// - it is useful for shortcut routing with ImGuiMultiSelectFlags_ClearOnEscape: so we can have Escape be used to clear selection THEN to exit child window.
|
||||
// - if it is costly for you to compute, but can easily tell if your selection is empty or not, you may pass 1, or use the ImGuiMultiSelectFlags_ClearOnEscape flag dynamically.
|
||||
ImGuiMultiSelectIO* ImGui::BeginMultiSelect(ImGuiMultiSelectFlags flags, int current_selection_size)
|
||||
// Passing 'selection_size' and 'items_count' parameters is currently optional.
|
||||
// - 'selection_size' is useful to disable some shortcut routing: e.g. ImGuiMultiSelectFlags_ClearOnEscape won't claim Escape key when selection_size 0,
|
||||
// allowing a first press to clear selection THEN the second press to leave child window and return to parent.
|
||||
// - 'items_count' is stored in ImGuiMultiSelectIO which makes it a convenient way to pass the information to your ApplyRequest() handler (but you may pass it differently).
|
||||
// - If they are costly for you to compute (e.g. external intrusive selection without maintaining size), you may avoid them and pass -1.
|
||||
// - If you can easily tell if your selection is empty or not, you may pass 0/1, or you may enable ImGuiMultiSelectFlags_ClearOnEscape flag dynamically.
|
||||
ImGuiMultiSelectIO* ImGui::BeginMultiSelect(ImGuiMultiSelectFlags flags, int selection_size, int items_count)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
ImGuiWindow* window = g.CurrentWindow;
|
||||
|
@ -7341,15 +7344,16 @@ ImGuiMultiSelectIO* ImGui::BeginMultiSelect(ImGuiMultiSelectFlags flags, int cur
|
|||
ImGuiMultiSelectState* storage = g.MultiSelectStorage.GetOrAddByKey(id);
|
||||
storage->ID = id;
|
||||
storage->LastFrameActive = g.FrameCount;
|
||||
storage->LastSelectionSize = current_selection_size;
|
||||
storage->LastSelectionSize = selection_size;
|
||||
storage->Window = window;
|
||||
ms->Storage = storage;
|
||||
|
||||
// Output to user
|
||||
ms->IO.Requests.resize(0);
|
||||
ms->IO.RangeSrcItem = storage->RangeSrcItem;
|
||||
ms->IO.NavIdItem = storage->NavIdItem;
|
||||
ms->IO.NavIdSelected = (storage->NavIdSelected == 1) ? true : false;
|
||||
ms->IO.Requests.resize(0);
|
||||
ms->IO.ItemsCount = items_count;
|
||||
|
||||
// Clear when using Navigation to move within the scope
|
||||
// (we compare FocusScopeId so it possible to use multiple selections inside a same window)
|
||||
|
@ -7375,7 +7379,7 @@ ImGuiMultiSelectIO* ImGui::BeginMultiSelect(ImGuiMultiSelectFlags flags, int cur
|
|||
{
|
||||
// Shortcut: Clear selection (Escape)
|
||||
// Only claim shortcut if selection is not empty, allowing further presses on Escape to e.g. leave current child window.
|
||||
if ((flags & ImGuiMultiSelectFlags_ClearOnEscape) && (current_selection_size != 0))
|
||||
if ((flags & ImGuiMultiSelectFlags_ClearOnEscape) && (selection_size != 0))
|
||||
if (Shortcut(ImGuiKey_Escape))
|
||||
request_clear = true;
|
||||
|
||||
|
@ -7826,17 +7830,22 @@ void ImGui::DebugNodeMultiSelectState(ImGuiMultiSelectState* storage)
|
|||
// if (req.Type == ImGuiSelectionRequestType_SetAll) { Clear(); if (req.Selected) { for (int n = 0; n < items_count; n++) { AddItem(n); } }
|
||||
// if (req.Type == ImGuiSelectionRequestType_SetRange) { for (int n = (int)ms_io->RangeFirstItem; n <= (int)ms_io->RangeLastItem; n++) { UpdateItem(n, ms_io->Selected); } }
|
||||
// }
|
||||
void ImGuiSelectionBasicStorage::ApplyRequests(ImGuiMultiSelectIO* ms_io, int items_count)
|
||||
void ImGuiSelectionBasicStorage::ApplyRequests(ImGuiMultiSelectIO* ms_io)
|
||||
{
|
||||
// For convenience we obtain ItemsCount as passed to BeginMultiSelect(), which is optional.
|
||||
// It makes sense when using ImGuiSelectionBasicStorage to simply pass your items count to BeginMultiSelect().
|
||||
// Other scheme may handle SetAll differently.
|
||||
IM_ASSERT(ms_io->ItemsCount != -1 && "Missing value for items_count in BeginMultiSelect() call!");
|
||||
IM_ASSERT(AdapterIndexToStorageId != NULL);
|
||||
|
||||
for (ImGuiSelectionRequest& req : ms_io->Requests)
|
||||
{
|
||||
if (req.Type == ImGuiSelectionRequestType_SetAll)
|
||||
Clear();
|
||||
if (req.Type == ImGuiSelectionRequestType_SetAll && req.Selected)
|
||||
{
|
||||
Storage.Data.reserve(items_count);
|
||||
for (int idx = 0; idx < items_count; idx++)
|
||||
Storage.Data.reserve(ms_io->ItemsCount);
|
||||
for (int idx = 0; idx < ms_io->ItemsCount; idx++)
|
||||
SetItemSelected(AdapterIndexToStorageId(this, idx), true);
|
||||
}
|
||||
if (req.Type == ImGuiSelectionRequestType_SetRange)
|
||||
|
|
Loading…
Reference in New Issue